C# .Net Core Unit Test could not verify ILogger method is called using Xunit

  Kiến thức lập trình

The Worker service is written in .Net Core 8.0 C#. There is custom logger is used to stored data in SQL Server Database and Serilog is used to write into text file.

added code in program.cs

var sqlLogger = provider.GetRequiredService<ILogger<SqlServerLogger>>();
builder.Services.AddLogging(configure =>
{
    configure.AddSerilog(logger,true);
    configure.AddProvider(new SqlServerLoggerProvider(ConStr, dbMiniLogLevel, sqlLogger));
}); 

The ILogger interface is injected in all classes for logging purpose. Based on config either both will work or any one works. The challenge is on unit test. The assertion has to be done whether Any ILogger method is called or specific method (LogInformation, LogError, etc.) and what message is passed in that method.

Please find the class


public class ScheduledWorkerService(ILogger<ScheduledWorkerService> logger,
        EmailServiceParallel emailServiceParallel,
        IOptions<Settings> Settings
        ) : IHostedService, IDisposable
{
    private Settings _Settings = Settings.Value;


    public Task StopAsync(CancellationToken cancellationToken)
    {
        logger.LogInformation("Worker service is stopping at: {time}", DateTimeOffset.Now);

        return Task.CompletedTask;
    }
}

Please find the Unit Test Using Xunit. Here Verifying the Ilogger is not working and get the error as

Unsupported expression: m => m.LogInformation(It.IsAny(), new[] { })
Extension methods (here: LoggerExtensions.LogInformation) may not be used in setup / verification expressions. Please advise the right way to check whether LogInformation, LogError is called with specific message if possible.

public class ScheduledWorkerServiceTest : ScheduledWorkerServiceFixture
{
    [Fact]
    public void StopAsync_StopsTimerAndLogs_Test()
    {
        // Arrange
        var cancellationTokenSource = new CancellationTokenSource();
        // Act
        var scheduledWorker = new ScheduledWorkerService(_mockLogger.Object, _EmailServiceParallel.Object, _mockOptions);
        var stopAsync = scheduledWorker.StopAsync(cancellationTokenSource.Token);
        // Assert
        // Ensure the returned task is Task.CompletedTask
        Assert.True(ReferenceEquals(stopAsync, Task.CompletedTask));
        
        // Assert
        _mockLogger.Verify(
            logger => logger.LogInformation(
                It.Is<string>(message => message == "Worker service is stopping at: {time}"),
                It.Is<object>(arg => arg is DateTimeOffset) // Verify argument is DateTimeOffset
            ),
            Times.Once);
            
        // Assert
        _mockLogger.Verify(
            logger => logger.LogInformation(
                It.Is<string>(message => message == "Worker service is stopping at: {time}"),
                new DateTimeOffsetMatcher()
            ),
            Times.Once);

        _mockLogger.Verify(m => m.LogInformation(It.IsAny<string>()), Times.AtLeastOnce);
        Additionally, you can assert that the message contains the specific text
        Assert.Contains("Worker service is stopping at:", _mockLogger.Invocations.Last().Arguments.First().ToString());
        
        _mockLogger.Verify(m => m.LogInformation("Worker service is stopping at: {time}", It.IsAny<DateTimeOffset>()), Times.Once);
        _mockLogger.Verify(m => m.LogInformation("Scheduled worker is stopping..."));

    }
}

LEAVE A COMMENT