1

I'm trying to unit test some usages of LoggerMessage.Define() using the Moq library in xUnit but can't figure it out. The below is an example of a logging function I've created and below that is a sample unit test that failed to check it was called.

LoggerMessage.Define() example:

public static class GlobalExceptionLoggerMessage
{
    public static Action<ILogger, string, Exception> GlobalException = LoggerMessage.Define<string>(
        LogLevel.Error,
        new EventId(StatusCodes.Status500InternalServerError, nameof(GlobalException)),
        "{Message}");

    public static void LogGlobalException(this ILogger logger, string message, Exception exception)
    {
        GlobalException(logger, message, exception);
    }
}

Unit test example I tried:

[Fact]
public void LogGlobalExceptionLogTest()
{
    var loggerMock = new Mock<ILogger<object>>();

    var exception = new Exception("Person must exist.");
    const string message = "Person must exist for an object.";

    loggerMock.Object.LogGlobalException(message, exception);

    loggerMock.Verify(
        x => x.Log(
            It.IsAny<LogLevel>(),
            It.IsAny<EventId>(),
            It.Is<It.IsAnyType>((v, t) => true),
            It.IsAny<Exception>(),
            It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)));
}

Can someone please shine some light on how I might fix this?

Thanks!

Benjamin
  • 353
  • 1
  • 4
  • 17
  • What are you actually trying to test here? That your custom delegate is invoked when `ILogger.Log` is called? – Ian Kemp Apr 02 '20 at 00:45
  • Great question Ian, wish I'd put more information here originally. I'm not completely sure of everything to test here but at the bare minimum I'd like to ensure that if I call the LogGlobalException() that some sort of log has been created, and then if possible I'd like to then test that the log matches what I entered: if the EventId matches, if the message matches, and if it's of the correct LogLevel. – Benjamin Apr 07 '20 at 05:08

1 Answers1

7

You need to do some additional set up. If you take a look inside the static Define method you'll see the following:

if (!logger.IsEnabled(logLevel))
  return;
Log(logger, arg1, exception);

You've not set up IsEnabled on your mocked logger, so it'll return a default bool (false) and won't invoke the Log method.

Taking your sample, if you add the following:

loggerMock.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true);

...your verify statement starts working.

Working example

rgvlee
  • 2,773
  • 1
  • 13
  • 20
  • Thank you very much! This has answered my question, I was missing the .Setup() call as you've stated. Really appreciate you going out of your way to create a GitHub example as well. – Benjamin Apr 07 '20 at 05:35