Serilog ILogger.ForContext 在 XUnit Mock 中抛出 NullReferenceException

Serilog ILogger.ForContext throwing NullReferenceException in XUnit Mock

我在尝试使用 Mock 对信号器组件进行单元测试时遇到问题。这是问题发生的地方

 _logger.LogInformation($"Registering a Station with id: {Id}" +
            $" with status: {Status}" +
            $"{(!string.IsNullOrEmpty(CommandId) ? $", with command: {CommandId}" : "")}", 
            LoggingConstants.Component.MessageHub,
            LoggingConstants.Class.Workstation, 
            !string.IsNullOrEmpty(AppointmentId) ? 
                AppointmentId : LoggingConstants.NoAppointmentId,
            LoggingConstants.NoConfirmationNumber);

LogInformation 定义为

logger.ForContext("Component", (object) component, false).ForContext("Class", (object) @class, 
false).ForContext("AppointmentId", (object) appointmentId, false).ForContext("ConfirmationNumber", 
(object) confirmationNumber, false).Information(message);

在 Xunit 单元测试 class 中,它被用作

public Mock<ILogger> MockLogger { get; set; }
MockLogger = new Mock<ILogger>();
Workstation = new Workstation(MockLogger.Object);

当单元测试为 运行 时,一旦遇到 _logger.LogInformation() 消息,它就会抛出一个

"System.NullReferenceException : Object reference not set to an instance of an object.
at LogInformation(ILogger logger, String message, String component, String class, String 
appointmentId, String confirmationNumber)"

为了验证它是因为 ForContext 而被抛出,使用了这个测试

_logger.Information("a") -> Works
_logger.ForContext("a", "a").Information("a") -> Exception is thrown

这是预期的...您正在创建 ILogger 的模拟,而没有设置 ForContext 应该 return 的内容,然后尝试使用 return ForContext 这显然是 null.

You have to call Setup on your mock to configure ForContext to return a valid ILogger.

例如

MockLogger.Setup(x => x.ForContext(It.IsAny<string>(), It.IsAny<string>(), false))
    .Returns(MockLogger.Object);

但是,您似乎没有测试任何有关日志记录的内容,只是创建了一个 ILogger 的模拟来满足被测试的 class 的依赖性。在那种情况下,您根本不必创建模拟......您可以简单地使用 Logger.None 这是一个什么都不做的 SilentLogger (它不记录也不抛出错误)。

例如

Workstation = new Workstation(Logger.None);