NSubstitute 创建替换实例的两个实例

NSubstitute creating two instances of substituted instance

我有一个基本的 ApiController 供我的控制器继承:

public BaseApiController(ILogger logger) : ApiController
{
    private readonly ILogger _logger;

    public BaseApiController(ILogger logger)
    {
        _logger = logger.ForContext("SomeContext");
    }
}

还有一个继承自基本控制器的简单控制器:

public SomeController : BaseApiController
{
    public SomeController(ILogger logger) : base(logger)
    { }

    public IHttpActionResult SomeAction()
    {
        _logger.Information("Start doing something...");

        //Do stuff...

        _logger.Information("End doing something...");

        return Ok();
    }
}

我已经使用 Xunit 和 Nsubstitute 为控制器创建了一个简单的测试:

public void SomeAction_ReturnsOk()
{
    //Arrange
    var logger = Substitute.For<ILogger>();
    var controller = new SomeController(logger) {
        Request = Substitute.For<HttpRequestMessage>()
    };

    //Act
    var result = controller.SomeAction();

    //Assert
    logger.ReceivedWithAnyArgs().Information(Arg.Any<string>());
}

在执行测试用例时,它失败并声明它已收到对 logger.Information() 方法的零次调用。调试 _receivedCalls 属性 (在替换的 ILogger 上) 时,如果调试上下文在测试用例本身内,则显示对 logger.ForContext() 方法的单个调用(在基础 class 构造函数上调用),但是在 controller.SomeAction() 方法的上下文中查看调试时,相同的 _receivedCalls 属性 按预期显示了对 logger.Information() 的两次调用,但没有显示对 ForContext().

的调用

所以在我看来,出于某种原因,Nsubstitute 正在创建替代 class 的两个单独实例,一个在基本控制器的上下文中,一个在实际控制器中 - 为什么会这样以及如何我避开了?

您需要像这样存根 ForContext return:

public void SomeAction_ReturnsOk()
{
    //Arrange
    var logger = Substitute.For<ILogger>();
    logger.ForContext(Arg.Any<string>()).Returns(logger);
    var controller = new SomeController(logger) {
        Request = Substitute.For<HttpRequestMessage>()
    };

    //Act
    var result = controller.SomeAction();

    //Assert
    logger.Received().Information(Arg.Any<string>());
}

我将断言更改为:

logger.Received().Information(Arg.Any<string>());

或:

logger.ReceivedWithAnyArgs().Information("");