【发布时间】:2015-12-21 12:16:36
【问题描述】:
我在 JUnit 测试中使用了 Mockito。测试是集成测试,测试整个场景,所以里面有很多断言和verify(mock)s。
我的问题是,我正在编写一些生产代码,做一些断言,然后验证模拟是否有效,直到有一个相同的模拟调用。查看简化代码:
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 也是一个选项,但由于它必须在验证和下一个相等的存根调用之间调用,所以我认为很难编写“好的”和正确的测试。应该有两种不同的 mocking 风格:
- “后置条件”像 Mockito 那样模拟
- “早期”模拟,这将是验证块后的隐式重置
类似:
earlyReset(m).after(
new Runnable() {
t.someMethodInvokingTwoStubs();
verify(m).someMethod1();
verify(m).someMethod2();
}
);
【问题讨论】:
-
试试这个answer
-
不要在一个测试方法中测试多个方法。一个测试应该有一个可以测试的东西,最好是一个可能失败的东西。测试多种方法会使您的测试更加复杂。将您的测试分成多个测试方法将解决这个问题。
-
@WoozyCoder 谢谢,编辑了我的帖子
-
@FlorianSchaetz 这是一个集成测试。它测试了一个有限状态机,分别是 TDD,因为我想编写一些生产代码来帮助我设计它。它使用的所有组件都经过单元测试,但状态机使用了非常多的反射,而我的测试是带有内部测试类和注释的场景。