【问题标题】:NSubstitute creating two instances of substituted instanceNSubstitute 创建两个被替换实例
【发布时间】:2017-07-21 21:41:42
【问题描述】:

我有一个基础 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() 方法 的单个调用(在基类构造函数),但是在 controller.SomeAction() 方法的上下文中查看调试时,相同的 _receivedCalls 属性显示了对 logger.Information() 的两次调用,正如预期的那样,但不是对ForContext().

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

【问题讨论】:

    标签: c# tdd xunit nsubstitute


    【解决方案1】:

    您需要像这样存根 ForContext 返回:

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

    【讨论】:

    • 我已经对 ForContext 进行了存根,但它仍然不起作用?有什么想法吗?
    • 不过你已经一针见血了,删除 ForContext() 调用并在构造函数中分配 _logger = logger 就可以了,所以看起来 ForContext 现在不起作用了?
    • 忽略我,方法是 ForContext(string, object) - 我把它存根为 ForContext(Any.Args(), Any.Args()),而不是 ForContext( Any.Args()、Any.Args()) 和 Returns() 方法不起作用。大声呼喊,感谢您的帮助。
    猜你喜欢
    • 2012-04-17
    • 1970-01-01
    • 2015-01-17
    • 1970-01-01
    • 2015-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多