mockito“verify”检查当前状态,但不重置模拟调用

时间:2015-12-21 12:16:37

标签: java junit mockito

我在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和下一个相等的存根调用之间调用,因此很难编写“好”和正确的测试,我认为。应该有两种不同的模拟风格:

  1. “后置条件”嘲笑Mockito做到了
  2. “早期”模拟,这将是在验证块
  3. 之后的隐式重置

    类似的东西:

    earlyReset(m).after(
        new Runnable() {
            t.someMethodInvokingTwoStubs();
    
            verify(m).someMethod1();
            verify(m).someMethod2();
        }
    );
    

2 个答案:

答案 0 :(得分:2)

我遇到类似的问题,决定使用clearInvocations()(在Mockito 2.1中到达)

https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html#clearInvocations-T...-

使用reset()的缺点是,您也松开了存根,clearInvocations()仅清除了调用。

答案 1 :(得分:0)

编写Mockito是为了避免脆弱,因此验证可以使最不具体的断言成为可能,允许实现在不改变测试的情况下进化。 如果您的测试系统对您多次调用这些方法并不重要,那么您不应该要求Mockito进行检查。

备选方案:

  • 使用atLeastatLeastOnce确保完成调用,而无需担心调用该方法的次数额外次。
  • 如果调用存根具有返回值,则推断系统使用状态断言来处理您已经存根的数据。
  • 如果您确实需要存根或验证行为来改变单个测试方法,那么您的模拟可能会超出Mockito所做的范围。对单个方法使用Answer,或者编写一个正确模拟互连方法的Fake手册。