设置模拟对象方法以改变输入和输出,警告:访问修改后的闭包

时间:2018-12-21 17:14:19

标签: c# moq

我想用一种方法创建一个模拟对象,该方法应该为每个输入返回不同的内容。当我尝试下面给出的代码时,我收到有关访问已修改闭包(即,访问i)的警告。如何正确设置模拟对象的FooMethod(i)以返回i*3

var ret = new Mock<FooClass>();

for(var i = 0; i < 10; i++){
    var bar = i*3;
    ret.Setup(x => x.FooMethod(i)).Returns(bar);
}

1 个答案:

答案 0 :(得分:3)

奥利维尔(Olivier)已在评论中说过。由于for变量的闭包语义,Moq在您的代码中看到的实际上是:

ret.Setup(x => x.FooMethod(10)).Returns(0);
ret.Setup(x => x.FooMethod(10)).Returns(3);
ret.Setup(x => x.FooMethod(10)).Returns(6);
ret.Setup(x => x.FooMethod(10)).Returns(9);
ret.Setup(x => x.FooMethod(10)).Returns(12);
ret.Setup(x => x.FooMethod(10)).Returns(15);
ret.Setup(x => x.FooMethod(10)).Returns(18);
ret.Setup(x => x.FooMethod(10)).Returns(21);
ret.Setup(x => x.FooMethod(10)).Returns(24);
ret.Setup(x => x.FooMethod(10)).Returns(27);

这当然不是您想要的。 (仅将Moq设置为值10,并且它将使用最新的Setup,因此返回27。)

请勿结束(捕获)for变量。一种解决方法是:

for (var i = 0; i < 10; i++) {
    var iCopy = i;
    ret.Setup(x => x.FooMethod(iCopy)).Returns(3 * iCopy);
}

在较新版本的C#中,foreach循环是不同的。因此,这可行:

foreach (var i in Enumerable.Range(0, 10)) {
    ret.Setup(x => x.FooMethod(i)).Returns(3 * i);
}

Moq提供了另一种不需要循环的方法。就像这样:

ret.Setup(x => x.FooMethod(It.IsAny<int>())).Returns((int i) => 3 * i);

当然,这是为 all i设置的。如果您不想这样做,可以更改为:

ret.Setup(x => x.FooMethod(It.Is((int i) => 0 <= i && i < 10))).Returns((int i) => 3 * i);