How to test the logs from ILogger in .NET
You sometimes need to validate that a log message is written to the log. In this post, I describe 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.
In this post, I will use the second strategy. The idea is to use a custom ILogger
implementation that stores all logs in-memory and keeps all details (state and scopes). I prefer this method as it is easier to debug a test. Indeed, you can see all logs using the debugger or using the ToString
method. Also, the test setup and the assertions are easy 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:
dotnet add package Meziantou.Extensions.Logging.InMemory
Then, you can use the package as follow in your unit test:
// 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 the WebApplicationFactory to create a test server and use the InMemoryLoggerProvider
as follow:
dotnet add package Microsoft.AspNetCore.Mvc.Testing
// 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!