我已经开始使用moq进行模拟。有人能解释我严格和非严格嘲笑的概念吗?它们如何在moq中使用?
修改 在哪种情况下我们使用哪种类型的模拟?
答案 0 :(得分:13)
我不确定moq具体,但这里是严格的模拟在Rhino中的工作方式。我声明我希望在我的对象foo.Bar
上调用foo
:
foo.Expect(f => f.Bar()).Returns(5);
如果调用代码
foo.Bar();
然后我很好,因为完全符合预期。
但是,如果调用代码是:
foo.Quux(12);
foo.Bar();
然后我的期望失败了,因为我没有明确期望拨打foo.Quux
。
总而言之,如果有任何不同于期望的话,严格的模拟会立即失败。另一方面,非严格模拟(或存根)将很乐意“忽略”对foo.Quux
的调用,并且应该为default(T)
返回T
foo.Quux
1}}。
Rhino的创建者recommends that you avoid strict mocks(并且更喜欢存根)因为您通常不希望您的测试在接收到如上所述的意外调用时失败。当您必须修复依赖于完全原始行为的数十个测试时,它会使您的代码重构变得更加困难。
答案 1 :(得分:3)
偶然遇到过Given / When / Then?
此模式出现在BDD的场景中,也与单元测试相关。
如果您正在设置上下文,那么您将使用该上下文提供的信息。例如,如果您通过Id查找某些内容,那就是上下文。如果它不存在,则测试将不会运行。在这种情况下,您希望使用NiceMock或Stub或其他 - Moq的默认运行方式。
如果您想验证结果,可以使用Moq的验证。在这种情况下,您希望记录相关的交互。幸运的是,这也是Moq默认的运行方式。如果您对该测试不感兴趣的事情,它不会抱怨。
当您不希望发生意外交互时,就会出现StrictMock。这是旧式模拟框架的运行方式。如果你正在做BDD风格的例子,你可能不会想要这个。与您分离您感兴趣的行为方面相比,它倾向于使测试变得有点脆弱且难以阅读。您必须对上下文和结果建立期望,对于将要发生的所有结果,无论如何他们是否感兴趣。
例如,如果您正在测试控制器并模拟验证器和存储库,并且想要验证是否已保存对象,则必须验证是否已经验证首先是对象。我更喜欢在单独的示例中看到行为的这两个方面,因为它使我更容易理解控制器的价值和行为。
在过去的四年里,我还没有找到一个需要使用严格模拟的例子 - 要么是我想要验证的结果(即使我验证它被调用的次数),要么是如果我对提供的信息做出正确回答,我可以告诉他们。所以回答你的问题:
答案 2 :(得分:0)
这是一个很好的article 我通常最终得到类似的东西
public class TestThis {
private final Collaborator1 collaborator1;
private final Collaborator2 collaborator2;
private final Collaborator2 collaborator3;
TestThis(Collaborator1 collaborator1, Collaborator2 collaborator2, Collaborator3 collaborator3) {
this.collaborator1 = collaborator1;
this.collaborator2 = collaborator2;
this.collaborator3 = collaborator3;
}
public Login login(String username) {
User user = collaborator1.getUser(username);
collaborator2.notify(user);
return collaborator3.login(user);
}
}
...我使用严格模拟为3个合作者测试登录(用户名)。我不知道如何永远不要使用Strict Mocks。
答案 3 :(得分:0)
我有一个简单的约定:
当被测系统(SUT)将调用委托给底层模拟层时,使用严格的模拟,而不是真正修改或应用传递给自身的参数的任何业务逻辑。
当SUT将业务逻辑应用于传递给自身的参数并将一些派生/修改的值传递给模拟层时,使用松散的模拟。
例如:
假设我们有数据库提供程序StudentDAL,它有两种方法:
数据访问界面如下所示:
public Student GetStudentById(int id);
public IList<Student> GetStudents(int ageFilter, int classId);
使用此DAL的实现如下所示:
public Student FindStudent(int id)
{
//StudentDAL dependency injected
return StudentDAL.GetStudentById(id);
//Use strict mock to test this
}
public IList<Student> GetStudentsForClass(StudentListRequest studentListRequest)
{
//StudentDAL dependency injected
//age filter is derived from the request and then passed on to the underlying layer
int ageFilter = DateTime.Now.Year - studentListRequest.DateOfBirthFilter.Year;
return StudentDAL.GetStudents(ageFilter , studentListRequest.ClassId)
//Use loose mock and use verify api of MOQ to make sure that the age filter is correctly passed on.
}