如何验证使用Moq调用"CallWithRef"方法?
public interface ITest
{
void CallWithoutRef(string value, List<string> errors);
void CallWithRef(string value, ref List<string> errors);
}
public class Foo
{
private ITest testInterface;
public Foo(ITest testInterface)
{
this.testInterface = testInterface;
}
public void DoStuff(string value)
{
var errorList = new List<string>();
testInterface.CallWithoutRef(value, errorList);
testInterface.CallWithRef(value, ref errorList);
}
}
[TestMethod]
public void VerifyTestInterfaceCalls()
{
var expectedValue = Path.GetRandomFileName();
var mockTestInterface = new Mock<ITest>();
var foo = new Foo(mockTestInterface.Object);
foo.DoStuff(expectedValue);
mockTestInterface.Verify(x => x.CallWithoutRef(expectedValue, It.IsAny<List<string>>()));
// Test fails here:
var errorList = It.IsAny<List<string>>();
mockTestInterface.Verify(x => x.CallWithRef(expectedValue, ref errorList));
}
Run Code Online (Sandbox Code Playgroud)
这在Moq 4.8.0中已经变得更好了,详情请参见其他答案It.Ref!
Verify在Moq中调用对ref参数执行严格的相等检查.当参数是引用类型时(如示例所示),只有当实际值和期望值是相同的引用时,Moq使用的参数匹配器才会成功.这是因为它用于验证相等性.object.ReferenceEquals(expected, actual)
在Moq快速入门中提到了这种行为(尽管可能会更加彻底):
// ref arguments
var instance = new Bar();
// Only matches if the ref argument to the invocation is the same instance
mock.Setup(foo => foo.Submit(ref instance)).Returns(true);
Run Code Online (Sandbox Code Playgroud)
在您的示例中,It.IsAny<List<string>>()实际上最后返回default(T),因此您要与创建null的新实例进行比较,根据匹配器的实现将失败.List<string>DoStuff
这显然是一个玩具示例,因此我无法建议您应该做什么,但如果您修改DoStuff为接受列表而不是创建自己的列表,您可以像这样测试它:
var errorList = It.IsAny<List<string>>();
// var errorList = new List<string>(); // also works
foo.DoStuff(expectedValue, errorList);
mockTestInterface.Verify(x => x.CallWithoutRef(expectedValue, It.IsAny<List<string>>()));
mockTestInterface.Verify(x => x.CallWithRef(expectedValue, ref errorList));
Run Code Online (Sandbox Code Playgroud)
从版本 4.8.0 开始,现在可以使用 Moq 来实现这一点。这是链接: https: //github.com/moq/moq4/issues/479
你可以像这样传递 errorList
ref It.Ref<List<string>>.IsAny
Run Code Online (Sandbox Code Playgroud)