我正在使用Mockito来编写我的测试用例。我有一个简单的类,其中包含一个我有兴趣测试的函数countPerson(boolean)
:
public class School {
//School is a singleton class.
public void countPerson(boolean includeTeacher) {
if (includeTeacher) {
countIncludeTeacher();
return;
}
countOnlyStudents();
}
public void countIncludeTeacher() {...}
public void countOnlyStudents() {...}
}
在我的单元测试中,我想测试 countPerson(boolean)
方法:
@Test
public void testCountPerson() {
School mSchool = School.getInstance();
School spySchool = Mockito.spy(mSchool);
spySchool.countPerson(true);
//Verify the function countIncludeTeacher is invoked once
verify(spySchool).countIncludeTeacher();
//Until here things are working well.
spySchool.countPerson(false);
//ERROR HERE when I try to verify the function has 0 times invoke
verify(spySchool, times(0)).countIncludeTeacher();
}
我有以下错误:
org.mockito.exceptions.verification.NeverWantedButInvoked: 学校计数包括教师((; 这里从来不想要: (学校测试.java 20(
为什么 0 次验证不起作用?
实际上,问题是每个verify
调用都是在同一个spySchool
实例上进行的。让我解释一下:
@Test
public void testCountPerson() {
School mSchool = School.getInstance();
School spySchool = Mockito.spy(mSchool); // a spy is created here, Mockito is listening in.
spySchool.countPerson(true); // real method is invoked
verify(spySchool).countIncludeTeacher(); // our spy identified that countIncludeTeacher was called
spySchool.countPerson(false); // real method is invoked
verify(spySchool, times(0)).countIncludeTeacher(); // our spy still identified that countIncludeTeacher was called, before it was called before
}
问题是在最新的verify
中,它失败了,因为之前在间谍上调用了countIncludeTeacher
方法,并且该调用未取消注册。
您可以使用 verifyNoMoreInteractions
来验证对象是否不再有交互。您也可以重置对象。
但请注意,这真的不推荐,引用Mockito Javadoc:
警告:一些做了大量经典的预期运行验证模拟的用户倾向于经常使用
verifyNoMoreInteractions()
,即使在每种测试方法中也是如此。 不建议在每种测试方法中使用verifyNoMoreInteractions()
。verifyNoMoreInteractions()
是交互测试工具包中的一个方便的断言。仅在相关时才使用它。滥用它会导致过度指定、更难维护的测试。您可以在此处找到进一步的阅读。
和
聪明的Mockito用户几乎不使用此功能,因为他们知道这可能是测试不佳的迹象。通常,您不需要重置模拟,只需为每种测试方法创建新的模拟即可。
与其
reset()
请考虑编写简单、小而集中的测试方法,而不是冗长、过度指定的测试。第一个潜在的代码异味reset()
在测试方法的中间。这可能意味着您测试太多了。遵循你的测试方法的耳语:"请让我们保持小,专注于单一行为"。
我绝对建议你把这个测试一分为二:一个用于true
情况,一个用于false
情况。
失败是因为您在测试中运行spySchool.countPerson(true)
时实际上确实调用了countIncludeTeacher()
。这会分支到您的其他函数,重新编码为对间谍对象的调用。
在当前设置中,您必须验证它只被调用一次,或者在运行第二个测试之前重置您的间谍对象实例。