Moq - 将参数从setup()传递到returns()

7

我不确定如何在Moq中从Setup()传递参数到Returns()。

这是一个例子:

public static IInterfaceHandler GetInterfaceHandlerMoq()
{
   // Defining the moq
   var moq = new Mock<IInterfaceHandler>();

   // Trying to set up a moq using another moq
   moq.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid>(), It.IsAny<string>()))
       .Returns((Guid guid, string value) => GetProgrammerMoq(guid, value));

   // Return mocked object
   return moq.Object;
}

注意GetProgrammerMoq()是一个库,将返回另一个Moq。以下是代码:

public static IProgrammer GetProgrammerMoq(Guid guid, string instName)
{
    // Create Moq
    var moq = new Mock<IProgrammer>();

    // Set up the returnables
    moq.Setup(o => o.InstanceName).Returns(programmer + "_" + instName);
    moq.Setup(o => o.Guid).Returns(guid);

    // Return mocked object
    return moq.Object;
}

注意GetProgrammerMoq()需要根据传递给CreateCommunicationInterface()的参数进行设置。

然后我的测试试图获取并使用Moq,但是返回的“p”为null(因为我猜测我的参数未正确传递给Returns())。
以下是测试草稿:

[Fact]
public void DoSomething()
{
    IInterfaceHandler test = ProgrammerMoqs.GetInterfaceHandlerMoq();

    Guid? g = new Guid();
    IProgrammer p = test.CreateCommunicationInterface(g, "test-boff");

    ...
}

1
所有这一切的目的是什么? - Robert Harvey
1
奇怪。乍一看,一切都看起来很好。请将行var moq = new Mock<IInterfaceHandler>();更改为var moq = new Mock<IInterfaceHandler>(MockBehavior.Strict);,然后重试并告诉我们发生了什么。 - quetzalcoatl
严格的行为:如果它能够正常工作但仍然返回null,那就更奇怪了。但我有点期望它会崩溃并抛出异常,说这个模拟没有设置调用,这意味着你设置的m.CreateCommunicationInterface不是你想象中的CreateCommunicationInterface。 - quetzalcoatl
@KlausGütter,那是一个打字错误,谢谢。虽然不是问题所在。 - stackMeUp
1
我是指:m.CreateCommunicationInterface(It.IsAny<Guid?>(), It.IsAny<string>())) - Klaus Gütter
显示剩余4条评论
1个回答

9

试试这个:

   var moq = new Mock<IInterfaceHandler>(MockBehavior.Strict);

MockBehavior.Strict:如果从 Mock 得到 NULL 值,那么总是尝试使用 MockBehavior.Strict。当一些设置没有准备好时,默认情况下 Moq 返回 NULL。但是使用 MockBehavior.Strict,则会抛出异常。每次调用模拟对象的任何内容时,如果缺少适当的设置,都将抛出异常。

如果在尝试使用 MockBehavior.Strict 时出现异常,则表示:

.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid>(), It.IsAny<string>()))

未能捕获调用,因此模拟默认返回NULL。

为什么未能捕获调用?有几种可能性:

  • CreateCommunicationInterface 可能被重载,而您的设置匹配了另一个意外的重载
  • 过滤器(It.IsAny..)未匹配实际参数
  • (..)

Klaus Gütter在评论中指出了 GuidGuid? 的区别。实际上,您正在使用的过滤器是 It.IsAny(),而在测试中您传递了:

Guid? g = new Guid();

g不是Guid类型的对象,而是Nullable<Guid>,因此寻找任何Guid的筛选器没有匹配。尽管表达式 It.IsAny<Guid>() 的结果符合方法所需的Guid?,但类型仍然不匹配,代码编译通过。

如果您尝试使用It.IsAny<Guid?>(),它可能会很好地匹配并返回您想要的结果。

moq.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid?>(), It.IsAny<string>()))
   .Returns((Guid? guid, string value) => GetProgrammerMoq(guid, value));

非常感谢,我已经修复了Guid的问题,并像你建议的那样添加了MockBehavior.Strict,看起来似乎可以工作。让我还原我的帖子中的编辑(我以为我已经在我的代码中修复了它,但仍然出现了问题 - 以为这不是问题的原因 :-) - stackMeUp
我现在不明白的是,为什么在GetInterfaceHandlerMoq()中的setup()之后调用"moq.VerifyAll();"时,会出现"This setup was not matched"类型的错误。这是因为所有方法都需要设置吗? - stackMeUp
@stackMeUp:在构造模拟对象时,不应调用VerifyAll方法。它不是一个设置方法!VerifyAll应该在测试的最后调用,即在所有东西都被设置和执行之后。如果我没记错,VerifyAll是一个断言,检查所有方法设置,并检查是否至少正确地调用了所有这些设置。它可以轻松地查看您设置的任何内容是否被忽略。理想情况下,如果您设置了某个东西,您希望它被使用,否则您首先就不会设置它,因此,如果有一些设置未被使用,则可能是错误的。 - quetzalcoatl
@stackMeUp:知道这一点后,在GetInterfaceHandlerMoq()中放置VerifyAll非常奇怪,因为它只是为测试构建一些对象。我不知道为什么VerifyAll会抛出你看到的异常,也许没问题,可能只是在说它试图查找过去方法调用的记录,并且未能匹配任何记录...我不记得了,我很少使用VerifyAll - 我更喜欢为我设置的每个方法进行显式验证。但是,请将其移动到测试的末尾,看看异常是否消失,这将告诉您/我们更多信息。 - quetzalcoatl
很好的解释,让人完全明白。我仍在探索Moq,所以有点难理解什么是最好使用的和如何使用。文档很少。 - stackMeUp

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