Serilog ILogger.ForContext throwing NullReferenceException in XUnit Mock
Asked Answered
H

1

6

I am having an issue when trying to unit test signalr components using Mock. Here is where the issue occurs

 _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 is defined as

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

In the Xunit Unit test class, it is being used as

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

When the unit test is run, once it hits that _logger.LogInformation() message, it throws a

"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)"

To verify that it is being thrown because of the ForContext, this test was used

_logger.Information("a") -> Works
_logger.ForContext("a", "a").Information("a") -> Exception is thrown
Hoarding answered 27/4, 2020 at 16:34 Comment(0)
S
11

That's expected... You are creating a mock of ILogger without setting up what ForContext should return, and then trying to use the return of ForContext which is obviously null.

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

e.g.

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

However, it looks you are not testing anything about logging and is just creating a mock of ILogger to satisfy the dependency of the class being tested. In that case, you don't have to create a mock at all... You can simply use Logger.None which is a SilentLogger that does nothing (it doesn't log nor throws errors).

e.g.

Workstation = new Workstation(Logger.None);
Servetnick answered 27/4, 2020 at 17:18 Comment(1)
I resolved the issue by adding a MockLogger.Setup(d => d.ForContext(It.IsAny<string>(), It.IsAny<string>(), false)).Returns(MockLogger.Object) underneath my initialization of mock logger. Thank you for your help!Hoarding

© 2022 - 2024 — McMap. All rights reserved.