Do you use Logging Fakes?


Unit tests are an essential part of ensuring .NET applications work correctly. However, when it comes to testing logging, things can get tricky. You don't want to rely on actual logging infrastructure like file writes or external logging systems during tests, as this could lead to unnecessary complexity and slow down your test suite.

Microsoft provides a simple solution with FakeLogger. This logger allows you to capture and verify logging calls in unit tests without needing to integrate with a real logging framework.

By incorporating FakeLogger into tests, you can ensure that the logging functionality is correct and meets your application's needs, all while maintaining fast and isolated tests.

What is the FakeLogger?

The FakeLogger is a mock logger provided by Microsoft for unit testing. It is part of the Microsoft.Extensions.Logging namespace and is used primarily in tests to verify that logging actions occur during the execution of the application, without sending log output to external destinations like the console or log files. Instead, it "fakes" the log output, allowing assertions to be made on the log entries.

The advantage of using FakeLogger is that it behaves like a real ILogger<T>, but it stores the logs in memory, making them available for examination during tests.

Benefits of using FakeLogger

  • No External Dependencies - Since FakeLogger does not actually write logs anywhere (such as to disk or a remote server), it keeps unit tests isolated and fast
  • Verify Log Entries - You can assert that certain log messages were generated during the execution of specific methods, helping to verify that logging statements are firing correctly
  • Easy Integration - FakeLogger is easy to integrate into any unit test framework, making it a seamless addition to your existing test suite

How to use FakeLogger

To get started with FakeLogger, you need to install the necessary package.

Then you can begin using the FakeLogger in unit tests. Here's how to use it:

Step 1: Create the FakeLogger

You start by creating an instance of FakeLogger<T>. This logger will capture any log entries for later verification.

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;

public class MyServiceTests
{
    [Fact]
    public void TestLoggingBehavior()
    {
        // Create a FakeLogger instance
        var logger = new FakeLogger<MyService>();

        // Create the service and pass in the fake logger
        var myService = new MyService(logger);

        // Act: Call a method that should log something
        myService.DoSomethingThatLogs();

        // Assert: Verify that a log entry was captured
        var logEntries = logger.GetLogEntries();
        Assert.Contains(logEntries, log => log.Message.Contains("Operation completed successfully"));
    }
}

Step 2: Define the MyService class

Here's an example class that uses logging. This class would typically contain methods that trigger logging when certain actions are taken.

public class MyService
{
    private readonly ILogger<MyService> _logger;

    public MyService(ILogger<MyService> logger)
    {
        _logger = logger;
    }

    public void DoSomethingThatLogs()
    {
        // Log a success message
        _logger.LogInformation("Operation completed successfully.");
    }
}

In the example above, MyService uses ILogger<MyService> to log an informational message when the DoSomethingThatLogs() method is called.

Step 3: Verify log entries

The next step in your unit test is to check the logs that were captured by FakeLogger. You can use methods like GetLogEntries() to retrieve the logs and assert on their contents.

var logEntries = logger.GetLogEntries();

Assert.Single(logEntries);
Assert.Equal("Operation completed successfully.", logEntries[0].Message);

This assertion checks that exactly one log entry was captured and that the message matches the expected text.

Advanced usage of FakeLogger

While the basic usage of FakeLogger is straightforward, you can also use it to verify log levels, event IDs, and other log-related data.

Verifying Log Levels

You can verify that the correct log level was used when logging messages. For example, if you're testing that an error is logged, you can assert that the log level is LogLevel.Error.

var logger = new FakeLogger<MyService>();
var myService = new MyService(logger);

myService.DoSomethingThatLogsError();  // Imagine this method logs an error

var logEntries = logger.GetLogEntries();
Assert.Contains(logEntries, log => log.LogLevel == LogLevel.Error);

Verifying Log Event IDs

In some scenarios, you may log messages with specific event IDs to categorize logs. FakeLogger captures these event IDs, allowing you to assert that they are set correctly.

public void LogWithEventId()
{
    _logger.LogInformation(new EventId(1001, "SomeEvent"), "Event 1001 triggered.");
}

var logger = new FakeLogger<MyService>();
var myService = new MyService(logger);

myService.LogWithEventId();

var logEntries = logger.GetLogEntries();
Assert.Contains(logEntries, log => log.EventId.Id == 1001 && log.Message.Contains("Event 1001 triggered"));
Tom Iwainski
We open source.Loving SSW Rules? Star us on GitHub. Star
Stand by... we're migrating this site to TinaCMS