我有一个基本的 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 和 Nreplace 为控制器创建了一个简单的测试:
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>());
}
执行测试用例时,它失败,指出它已收到对记录器的零调用。信息() 方法。调试 _receivedCalls 属性(在替换的 ILogger 上)时,如果调试上下文位于测试用例本身内,则它会显示对 logger.ForContext()
方法的单个调用(在基类构造函数上调用),但是在控制器上下文中查看调试时。SomeAction() 方法,相同的 _receivedCalls
属性按预期显示对logger.Information()
的两个调用,但不显示对ForContext()
的调用。
所以在我看来,出于某种原因,Nsubstitute 正在创建替代类的两个独立实例,一个在基本控制器的上下文中,另一个在实际控制器中 - 为什么会这样,我该如何避免它?
像这样存根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("");