我有一个接受IEnumerable
的方法:
MyMethod(IEnumerable<MyClass> myParameter)
现在,我正在编写以下代码来模拟服务:
var array1 = new MyClass[0];
var array2 = new MyClass[0];
_service
.Setup(s => s.MyMethod(array1))
.Returns(value1);
_service
.Setup(s => s.MyMethod(array2))
.Returns(value2);
最后,我在被测系统内部使用两个数组对服务进行了两次调用:
_service.MyMethod(array1);
_service.MyMethod(array2);
我期望从这些调用中获得value1
和value2
,但实际上,后一个调用将覆盖第一个调用,而我从这两个调用中仅获得value2
。
这是Moq中的错误,还是安装程序不将IEnumerable
视为单独的对象,而是尝试对其进行扩展并比较所有元素或某些内容(导致两个空数组是同一安装调用) )?
答案 0 :(得分:3)
当使用Moq在一个方法上创建多个设置时,除非设置是有条件的(它们在参数上指定了某些条件),否则每个后续设置都将替换以前的设置。参见this answer。
您可以通过指定参数必须与要传递的参数匹配来修正代码:
[Test]
public void MyTest()
{
var service = new Mock<MyClass>();
var array1 = new MyClass[0];
var array2 = new MyClass[0];
var value1 = "value1";
var value2 = "value2";
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array1))).Returns(value1);
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array2))).Returns(value2);
Assert.AreEqual(value1, service.Object.MyMethod(array1));
Assert.AreEqual(value2, service.Object.MyMethod(array2));
}
答案 1 :(得分:2)
您描述的行为是 moq
的默认行为,您可以看到它here。它确实可以枚举并调用IEnumerable.SequenceEqual
。但是,这是默认行为(如果您使用实例Constant
匹配器进行设置),则可以覆盖它。一种方法是Owen建议使用It.Is<T>
匹配器。
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array1)))
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array2)))
请注意,==
默认执行ReferenceEquals()
,因此这将进行不同的不可覆盖的设置。