对于嘲笑的一般背景,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
类中,以便我们可以配置其行为。
所以现在我们有一个模拟对象,我们经常需要配置它如何响应调用它的方法。这样,我们就可以测试我们的系统如何对它做出反应。第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
的实现,可:
- 为
"ping"
回报true
在一个测试
- 为
"pong"
在另一项测试中最后一次测试返回true
- 回报
false
任何参数
您可以创建自己的模仿对象有这种行为,例如:
public class MockFoo : IFoo
{
string trueValue;
public MockFoo(string trueValue)
{
this.trueValue = trueValue;
}
public bool DoSomething(string value)
{
return value == trueValue;
}
}
但是,这是一种当你有复杂的痛苦逻辑,多参数,或一对多的依赖关系;它只是不能很好地扩展。这是模拟对象和Moq可以让事情变得简单的地方。在起订量相同的设置三个测试是:
mock.Setup(foo => foo.DoSomething("ping")).Returns(true);
mock.Setup(foo => foo.DoSomething("pong")).Returns(true);
mock.Setup(foo => foo.DoSomething(It.IsAny<string>())).Returns(false);
在我看来,这是更简单,更表现你期待怎样的IFoo
依赖的行为。
至于指南,我认为你最好带着一个嘲笑的指南,而不是一个Moq指定的指南。 Moq只是一个使得使用模拟对象更容易的库,对于使用Moq的机制来说,这是一个很好的参考。有几十个嘲笑教程和指南,只是寻找一些。请记住,它直到我开始使用它时才真正“点击”我。找一个coding kata并尝试自己嘲笑!
几年前的单元测试艺术[第二版](https://www.manning.com/books/the-art-of-unit-testing-second-edition),这是仍在印刷品AFAIK – NikolaiDante
@NikolaiDante - 哇!甚至没有检查。谢谢! – webworm