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.

Software Engineer and Architect focusing on .NET and Microsoft technologies. Microsoft MVP. Practitioner of clean code. #solid #tdd #ddd #cqrs #es #graphql

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store