无法理解Moq

时间:2016-01-08 17:53:58

标签: c# unit-testing moq

我无法掌握Moq框架。他们从Moq网站上给出了这个例子......

// Assumptions:
public interface IFoo {
   public bool DoSomething(string);
   public bool TryParse(string, out string));
}

var mock = new Mock<IFoo>();
mock.Setup(foo => foo.DoSomething("ping")).Returns(true);

Moq设置在这里做什么?

// out arguments
var outString = "ack";
// TryParse will return true, and the out argument will return "ack", lazy evaluated
mock.Setup(foo => foo.TryParse("ping", out outString)).Returns(true);

这里的问题是......正在设置什么?

有没有人知道Moq的指南可能会更深入?我读了这篇SO post,其中推荐了这本书The Art of Unit Testing with Examples in .NET,但这本书已经很老了,已经绝版了。

1 个答案:

答案 0 :(得分:4)

关于模拟的一般背景,this answer可以很好地解释它以及为什么你可能想在单元测试中使用它。

具体来说,Moq是一个允许您轻松创建模拟对象并控制其行为的库。使用示例进行描述最简单,所以让我们看看您的第一个代码示例:

public interface IFoo {
   public bool DoSomething(string);
   public bool TryParse(string, out string));
}

/* 1 */ var mock = new Mock<IFoo>();
/* 2 */ mock.Setup(foo => foo.DoSomething("ping")).Returns(true);

第1行创建IFoo接口的模拟实现。在幕后,Moq正在使用Castle DynamicProxy库来动态创建IFoo的具体实现,然后将其包装在自己的Mock类中,以便我们可以配置它的行为。 / p>

现在我们有了一个模拟对象,我们经常需要配置它如何响应调用它的方法。这样,我们就可以测试我们的测试系统对它的反应。第2行的Setup方法就是这样做的,告诉我们的模拟对象在调用true并且参数等于DoSomething时返回"ping"。想象一下,您正在使用此模拟来测试如下所示的类:

public class TestObject 
{
    public string TestMethod(IFoo foo)
    {
        if (foo.DoSomething("ping"))
            return "ping";
        else if (foo.DoSomething("pong"))
            return "pong";
        return "blah";
    }
}

要获得完整的测试覆盖率,您需要IFoo的实施,可以:

  1. 在一次测试中返回true "ping"
  2. 在另一个测试中为true返回"pong"
  3. 为最后一次测试中的任何参数返回false
  4. 可以创建自己的具有此行为的模拟对象,例如:

    public class MockFoo : IFoo
    {
        string trueValue;
    
        public MockFoo(string trueValue)
        {
            this.trueValue = trueValue;
        }
    
        public bool DoSomething(string value)
        {
            return value == trueValue;
        }
    }
    

    但是当你有复杂的逻辑,多个参数或许多依赖关系时,那会很痛苦;它只是没有很好的扩展。这就是模拟对象和Moq可以让事情变得简单的地方。 Moq中三个测试的相同设置是:

    1. mock.Setup(foo => foo.DoSomething("ping")).Returns(true);
      
    2. mock.Setup(foo => foo.DoSomething("pong")).Returns(true);
      
    3. mock.Setup(foo => foo.DoSomething(It.IsAny<string>())).Returns(false);
      
    4. 在我看来,这对于你期望IFoo依赖行为的表现更简单,更具表现力。

      至于指南,我认为你最好通过一般的模拟指南,而不是Moq特定的指南。 Moq只是一个使模拟对象更容易使用的库,而Quickstart对于使用Moq的机制来说是一个非常好的参考。有几十个模拟教程和指南,只是寻找一些。请记住,它并没有真正&#34;点击&#34;直到我开始使用它们。找一个coding kata并尝试自己嘲笑!