Moq设置会将所有空的可枚举/数组视为相同的参数

时间:2019-05-03 10:27:18

标签: c# moq

我有一个接受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);

我期望从这些调用中获得value1value2,但实际上,后一个调用将覆盖第一个调用,而我从这两个调用中仅获得value2

>

这是Moq中的错误,还是安装程序不将IEnumerable视为单独的对象,而是尝试对其进行扩展并比较所有元素或某些内容(导致两个空数组是同一安装调用) )?

2 个答案:

答案 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(),因此这将进行不同的不可覆盖的设置。