使用Moq验证带有ref参数的调用

7
我该如何使用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));
}
2个回答

8

在Moq 4.8.0中,这方面有了很大改进,有关It.Ref的详细信息,请参见此处的其他答案!


在 Moq 中,对于 ref 参数,Verify 调用执行严格的相等性检查。当参数是引用类型(如您的示例中),Moq 使用的参数匹配器 仅在实际值和预期值是相同引用时才成功。这是因为它使用 object.ReferenceEquals(expected, actual) 来验证相等性。
这种行为在Moq Quickstart中提到(虽然可能需要更详细的说明)。
// 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);

在你的示例中,It.IsAny<List<string>>() 实际上最终返回了 default(T),因此你正在将 null 与在 DoStuff 中创建的一个新的 List<string> 实例进行比较,根据匹配器的实现,这会导致测试失败。
显然,这是一个玩具示例,所以我不能建议你应该做什么,但如果你修改 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));

1
如果您正在查看此答案,并且您拥有v4.8.0+,请不要像我一样没有注意到下面的答案,网址为https://dev59.com/YIPba4cB1Zd3GeqPqUww#49537043,作者是@Spencer-Sutton。 - Shereef Marzouk
1
谢谢@ShereefMarzouk,我添加了一些文本来指向另一个答案。 - Patrick Quirk
太棒了,谢谢! - Shereef Marzouk

7

如果您正在使用 mockedBla.Protected()using moq.Protected;,则应该使用 ItExpr 而不是 It - Shereef Marzouk
这应该是被接受的答案。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接