Using Moq to Verify your Logging is working

Using Moq to Verify your Logging is working

Introduction

Mocking ILogger<T> for testing methods that use logging in C# can be done effectively using the Moq library. The ILogger<T> interface is commonly used in .NET applications for logging purposes. Here’s how you can mock the LogInformation method specifically.

Steps to Mock ILogger<T>.LogInformation

Add the Required NuGet Packages

Ensure you have the Moq and Microsoft.Extensions.Logging.Abstractions packages added to your test project.

Create a Mock Instance of ILogger<T>

Use Moq to create a mock instance of ILogger<T>.

var loggerMock = new Mock<ILogger<MyClass>>();

MyClass can be any class in your application; typically, it’s the class where the logger is injected.

Set Up the Mock to Capture Log Information Calls

You can use the Callback method of Moq to capture the arguments passed to LogInformation.

List<LogLevel> logLevels = new List<LogLevel>();
List<string> logMessages = new List<string>();

loggerMock.Setup(
    x => x.Log(
        It.IsAny<LogLevel>(),
        It.IsAny<EventId>(),
        It.IsAny<object>(),
        It.IsAny<Exception>(),
        It.IsAny<Func<object, Exception, string>>())
).Callback<LogLevel, EventId, object, Exception, Func<object, Exception, string>>(
    (level, eventId, state, exception, func) =>
    {
        logLevels.Add(level);
        logMessages.Add(func(state, exception));
    }
);

This setup captures any log level and message passed to the logger.

Use the Mock in Your Tests

Inject this mock logger into the class or method you are testing. After the test runs, you can assert against logLevels and logMessages to verify that LogInformation was called as expected.

Example of an Assertion

After running your test, you can assert that the LogInformation was called with the expected message.

Assert.That(logLevels, Does.Contain(LogLevel.Information), "logLevels should contain LogLevel.Information.");

Assert.That(logMessages, Has.Some.Contains("MyMethod was called."), "logMessages should contain 'MyMethod was called.'.");

Example Scenario

Let’s say you have a method in MyClass that logs some information, and you want to test that this logging occurs as expected:

public class MyClass
{
    private readonly ILogger<MyClass> _logger;

    public MyClass(ILogger<MyClass> logger)
    {
        _logger = logger;
    }

    public void MyMethod()
    {
        // Some logic...
        _logger.LogInformation("MyMethod was called.");
    }
}

In your test, after you set up the mock and execute MyMethod, you can assert whether “MyMethod was called.” was logged at the Information level.

Conclusion

Using Moq to Verify calls are made makes it a powerful too. Mocking ILogger<T> with Moq allows you to verify that your logging statements are being called as expected without relying on an actual logging provider.

This is particularly useful in unit testing scenarios where you want to ensure your logging logic is correctly integrated without the overhead of real logging mechanisms.

You can find the official Moq documentation here: – https://documentation.help/Moq/

I have written a few posts that use Moq here: – Underused Moq Features, Unit Testing Mininal APIs.

Stephen

Hi, my name is Stephen Finchett. I have been a software engineer for over 30 years and worked on complex, business critical, multi-user systems for all of my career. For the last 15 years, I have been concentrating on web based solutions using the Microsoft Stack including ASP.Net, C#, TypeScript, SQL Server and running everything at scale within Kubernetes.