Sometimes you need to validate that your code writes the expected log messages. This post covers how to unit test ILogger in .NET Core.
There are multiple strategies:
- You can use a mock framework like Moq to mock the
ILogger interface and validate the right calls are made. - You can store all logs in-memory and assert the collection.
- You can use a file logger and assert the log file.
- Etc.
I will use the second strategy. The idea is to use a custom ILogger implementation that stores all logs in-memory and retains all details (state and scopes). This approach is easier to debug: you can inspect all logs using the debugger or the ToString method, and both the test setup and assertions are straightforward to write.
You can use the Meziantou.Extensions.Logging.InMemory NuGet package to get an in-memory logger provider. You can install it using the following command:
Shell
dotnet add package Meziantou.Extensions.Logging.InMemory
Then, you can use the package as follows in your unit test:
C#
// Create the logger
using var loggerProvider = new InMemoryLoggerProvider();
var logger = loggerProvider.CreateLogger("MyLogger");
// Call the method to test
MethodToTest(logger);
// Validate the logs
Assert.Empty(loggerProvider.Logs.Errors);
Assert.Single(loggerProvider.Logs, log => log.Message.Contains("test") && log.EventId.Id == 1);
If you are testing an ASP.NET Core application, you can use WebApplicationFactory to create a test server and use the InMemoryLoggerProvider as follows:
Shell
dotnet add package Microsoft.AspNetCore.Mvc.Testing
C#
// Create the in-memory logger provider
using var loggerProvider = new InMemoryLoggerProvider();
// Register the provider when creating the WebApplicationFactory
using var factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureLogging(builder =>
{
builder.Services.AddSingleton<ILoggerProvider>(loggerProvider);
});
});
// Call the API
using var client = factory.CreateClient();
var str = await client.GetStringAsync("/me");
// Validate the logs
var warning = Assert.Single(loggerProvider.Logs.Warnings);
Assert.Equal("Demo sample", warning.Message);
Do you have a question or a suggestion about this post? Contact me!