我在JUnit测试中使用Mockito。测试是一个集成测试,测试整个场景,因此有许多断言和verify(mock)
。
我的问题是,我正在编写一些生产代码,做一些断言,然后验证有效的模拟,直到有一个相同的模拟调用。请参阅简化代码:
interface I {
void m1();
void m2();
}
// some decorator
class T implements I {
public T(I decorated) {
/*...*/
}
/* ... */
}
public void testInvalid() {
I m = mock(I.class);
T t = new T(m);
t.m1();
assertEquals("m1", t.getLastMethod());
verify(m).m1();
t.m2();
assertEquals("m2", t.getLastMethod());
verify(m).m2();
t.m1();
assertEquals("m1", t.getLastMethod());
verify(m).m1();
// TooManyActualInvocations t.m1(): Wanted 1 time, but was 2 times ...
}
public void testValid() {
I m = mock(I.class);
T t = new T(m);
t.m1();
assertEquals("m1", t.getLastMethod());
t.m2();
assertEquals("m2", t.getLastMethod());
t.m1();
assertEquals("m1", t.getLastMethod());
verify(m, times(2)).m1();
verify(m).m2();
}
一个想法是在最后验证模拟,但是假设存在一个小的愚蠢的实现错误导致调用方法m1两次并且m2一次但不像我在testInvalid
中所期望的那样但在测试结束了。我希望我的测试尽早失败。我该如何做到这一点?
谢谢。
感谢@Woozy Coder:
没有提到,reset
也是一个选项,但由于必须在verify和下一个相等的存根调用之间调用,因此很难编写“好”和正确的测试,我认为。应该有两种不同的模拟风格:
类似的东西:
earlyReset(m).after(
new Runnable() {
t.someMethodInvokingTwoStubs();
verify(m).someMethod1();
verify(m).someMethod2();
}
);
答案 0 :(得分:2)
我遇到类似的问题,决定使用clearInvocations()
(在Mockito 2.1中到达)
使用reset()
的缺点是,您也松开了存根,clearInvocations()
仅清除了调用。
答案 1 :(得分:0)
编写Mockito是为了避免脆弱,因此验证可以使最不具体的断言成为可能,允许实现在不改变测试的情况下进化。 如果您的测试系统对您多次调用这些方法并不重要,那么您不应该要求Mockito进行检查。
备选方案:
atLeast
或atLeastOnce
确保完成调用,而无需担心调用该方法的次数额外次。