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.