Unit-testing ILogger in ASP.NET Core
ASP.NET Core makes it extremely easy to log information, warnings, errors and the like by injecting the generic ILogger<T>
interface. However, unit-testing becomes a little bit harder, so let us see why and how we can solve this with ease.
In the examples below, we will be using the mocking framework Moq to verify that a certain message is getting logged.
Service under test
Let’s take a closer look to a service responsible for sending template based e-mails.
Writing the obvious test
Now, we want to make sure that an error is being logged in case _smtpMailer.Send
throws an exception.
The first attempt would be to write the test like this:
However, since LogError
/ LogInformation
/ LogWarning
etc are extensions methods, we’re getting the following run-time exception:
Message: System.NotSupportedException : Invalid verify on an extension method.
As it turns out, the ILogger<>
interface is pretty simple, but contains a rather complex Log
method that is harder to setup or verify in your unit-tests.
Elegant solution
An elegant solution to this problem is to create a small abstract logger class in our unit-test project:
…and use a mock of that class in our tests. We can now rewrite the test like this:
Conclusion
In this post we have seen one way to keep unit-testing using ILogger<T>
clean and easy. Of course this is not the only way, but from the many solutions I’ve tried I found this one to be the most elegant and practical solution.
If you have another neat way to get around with tests like this, I’d be glad to hear your solution.