最小起订量对象设置范围/上下文因构建器模式单元测试和 Web api 控制器而丢失
MOQ object setup scope / context being lost with builder pattern unit test and web api controller
我正在为控制器编写单元测试并且 运行 遇到了一个问题,在我注入模拟对象时似乎没有设置它。但是,如果我在控制器端点创建模拟对象,一切正常。最后,为了使事情更加复杂,我正在通过流畅的构建器模式进行单元测试。
首先这是一个工作片段:
public HttpResponseMessage AddSlot(AddSlotRequest requestList)
{
var errorInfo = new List<ErrorInfo>();
Mock<IdatRepository> _xRepository = new Mock<IdatRepository>();
_xRepository.Setup(x => x.GetDat(It.IsAny<Guid>(), ref errorInfo))
.Returns(new Dat());
....snip....
var crt = _xRepository.Object.GetDat(datId, ref errorInfo);
//crt object returned as expected from mock
....snip
}
现在请注意,这会涉及更多内容。
首先,我的控制器由构建器创建:
public class AddSlotControllerBuilder
{
//private backing field for fluent methods to act upon
private Mock<IdatRepository> _xRepository = new Mock<IdatRepository>();
//exposed property for external interactions...
//not doing any yet but had plans so that is why it is here
public Mock<IdatRepository> MoqdatRepository { get; private set; }
//following the builder pattern the build method is called to return
//the object after configuration complete
public AddSlotController Build()
{
var errorInfo = new List<ErrorInfo>();
_xRepository.Setup(x => x.GetDat(It.IsAny<Guid>(), ref errorInfo)).Returns(new Dat());
//assign private mock field to property
MoqdatRepository = _xRepository;
return new AddSlotController(_xRepository.Object);
}
}
现在我的单元测试使用构建器:
[TestMethod]
public void AddValidPickupSlotCorrectResponse()
{
var errorInfo = new List<ErrorInfo>(); //ref field
//arrange
//1. controller
AddSlotController controller = new AddSlotControllerBuilder().Build();
//skipping APSR for brevity
//act
controller.AddPickupSlot(APSR);
}
终于在控制器中了
var crt = _xRepository.Object.GetDat(datId, ref errorInfo);
//crt is null????
任何我偏离轨道的指示都将不胜感激。
此问题是由您的 GetDat
方法采用 ref 参数引起的。本质上,除非您将相同的实例传递给您传递给 Setup
的调用,否则它将无法匹配设置。可以找到更多详细信息 here,以及使用 RhinoMocks 的建议解决方法。我认为它可能也适用于 NSubstitute,但我还没有测试过。
看看你在做什么,你真的需要 errorInfo 由 ref 传递吗?它是列表 class 的一个实例,您的存储库可能会添加到该列表中。真的需要将 errorInfo 重新分配给 class 的另一个实例吗?如果没有,那么您可以将签名更改为非参考签名,然后按如下方式设置您的模拟(两者都应该有效):
_xRepository.Setup(x => x.GetDat(It.IsAny<Guid>(), It.IsAny<List<ErrorInfo>>()))
.Returns(new Dat());
或
_xRepository.Setup(x => x.GetDat(It.IsAny<Guid>(), errorInfo))
.Returns(new Dat());
我正在为控制器编写单元测试并且 运行 遇到了一个问题,在我注入模拟对象时似乎没有设置它。但是,如果我在控制器端点创建模拟对象,一切正常。最后,为了使事情更加复杂,我正在通过流畅的构建器模式进行单元测试。
首先这是一个工作片段:
public HttpResponseMessage AddSlot(AddSlotRequest requestList)
{
var errorInfo = new List<ErrorInfo>();
Mock<IdatRepository> _xRepository = new Mock<IdatRepository>();
_xRepository.Setup(x => x.GetDat(It.IsAny<Guid>(), ref errorInfo))
.Returns(new Dat());
....snip....
var crt = _xRepository.Object.GetDat(datId, ref errorInfo);
//crt object returned as expected from mock
....snip
}
现在请注意,这会涉及更多内容。
首先,我的控制器由构建器创建:
public class AddSlotControllerBuilder
{
//private backing field for fluent methods to act upon
private Mock<IdatRepository> _xRepository = new Mock<IdatRepository>();
//exposed property for external interactions...
//not doing any yet but had plans so that is why it is here
public Mock<IdatRepository> MoqdatRepository { get; private set; }
//following the builder pattern the build method is called to return
//the object after configuration complete
public AddSlotController Build()
{
var errorInfo = new List<ErrorInfo>();
_xRepository.Setup(x => x.GetDat(It.IsAny<Guid>(), ref errorInfo)).Returns(new Dat());
//assign private mock field to property
MoqdatRepository = _xRepository;
return new AddSlotController(_xRepository.Object);
}
}
现在我的单元测试使用构建器:
[TestMethod]
public void AddValidPickupSlotCorrectResponse()
{
var errorInfo = new List<ErrorInfo>(); //ref field
//arrange
//1. controller
AddSlotController controller = new AddSlotControllerBuilder().Build();
//skipping APSR for brevity
//act
controller.AddPickupSlot(APSR);
}
终于在控制器中了
var crt = _xRepository.Object.GetDat(datId, ref errorInfo);
//crt is null????
任何我偏离轨道的指示都将不胜感激。
此问题是由您的 GetDat
方法采用 ref 参数引起的。本质上,除非您将相同的实例传递给您传递给 Setup
的调用,否则它将无法匹配设置。可以找到更多详细信息 here,以及使用 RhinoMocks 的建议解决方法。我认为它可能也适用于 NSubstitute,但我还没有测试过。
看看你在做什么,你真的需要 errorInfo 由 ref 传递吗?它是列表 class 的一个实例,您的存储库可能会添加到该列表中。真的需要将 errorInfo 重新分配给 class 的另一个实例吗?如果没有,那么您可以将签名更改为非参考签名,然后按如下方式设置您的模拟(两者都应该有效):
_xRepository.Setup(x => x.GetDat(It.IsAny<Guid>(), It.IsAny<List<ErrorInfo>>()))
.Returns(new Dat());
或
_xRepository.Setup(x => x.GetDat(It.IsAny<Guid>(), errorInfo))
.Returns(new Dat());