如何在模拟中为不同的输入返回不同的值?

时间:2018-09-10 18:24:48

标签: c# mocking moq

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var o1 = new XmlDocument();
        var o2 = new XmlDocument();

        var mock = new Mock<ITestInterface>();
        mock.Setup(m => m.TestMethod(o1)).Returns(1);
        mock.Setup(m => m.TestMethod(o2)).Returns(2);

        Assert.AreEqual(1, mock.Object.TestMethod(o1));
        Assert.AreEqual(2, mock.Object.TestMethod(o2));
    }
}

public interface ITestInterface
{
    int TestMethod(object input);
}

为什么模拟总是返回第二个值?如果我将XmlDocument切换到其他任何对象(对象,StringBuilder等),它将按预期工作。

2 个答案:

答案 0 :(得分:3)

我以为它也可以按照您的预期工作,但我也得到相同的结果。但是,如果改为按以下方式进行设置,则它将按您希望的那样工作。

mock.Setup(m => m.TestMethod(It.Is<XmlDocument>(y => ReferenceEquals(o1, y)))).Returns(1);
mock.Setup(m => m.TestMethod(It.Is<XmlDocument>(y => ReferenceEquals(o2, y)))).Returns(2);

在我进一步测试时,我注意到的另一件事是,如果您设置InnerXml,一切将按照您最初设置的方式工作。

var doc1 = new XmlDocument { InnerXml = "<root1 />" };
var doc2 = new XmlDocument { InnerXml = "<root2 />" };;
mock.Setup(x => x.TestMethod(doc1)).Returns(1);
mock.Setup(x => x.TestMethod(doc2)).Returns(2);

Console.WriteLine($"{mock.Object.TestMethod(doc1)}");
Console.WriteLine($"{mock.Object.TestMethod(doc2)}");

如果您将两个InnerXml的值设置为相同的字符串,它甚至可以工作。这确实是个谜,我一直无法解释。

答案 1 :(得分:1)

我运行了您的代码,并遇到了同样的问题。在第一个使用Message: Assert.AreEqual failed. Expected:<1>. Actual:<2>.的断言中,准确地运行代码的发布方式失败。当我将o1和o2更改为object而不是XmlDocument时,它按预期工作。

奇怪的是,将2条设置行更改为以下内容将使其产生正确的结果:

mock.Setup(m => m.TestMethod(It.Is<XmlDocument>(x => x == o1))).Returns(1);
mock.Setup(m => m.TestMethod(It.Is<XmlDocument>(x => x == o2))).Returns(2);

这很奇怪,因为我认为您的2条设置行的行为应与我的完全一样,但是在这种情况下,我的设置行却可以正常工作,而您的行却不行。我假设存在我不知道的差异,或者Moq存在一个导致此错误的错误。