Mockito验证了对模拟对象的最后一次调用

时间:2018-05-24 07:43:28

标签: java mockito call verify

我有一些需要测试的逻辑,例如:

| count | count | count | count | 
| 1     | 1     | 1     | 0     |

我已经在我的测试中模拟了A,我可以测试add方法在参数(“2”)上调用一次,例如:

{
    ...
    A.add("1");
    ...
    A.add("what ever");
    ...
    A.add("2");
    A.delete("5");
    ...
}

我的问题是如何测试我是否可以验证方法add的最后一次调用是add(“2”)而不是其他参数。

由于上述测试无法捕获,如果有人偶然添加了另一个调用,例如add(“3”)。请注意,之后我们不再关心A上的其他方法调用。我们也不关心调用方法的次数,调用方法的顺序。 这里的关键点是我们是否可以验证某个mockedObject的某个方法的最后一个真实参数。

如果你问为什么你需要这样的功能,我会说在现实世界中我们可能需要处理一些设置某些东西并且最后一组获胜的逻辑,并且为了避免某人意外设置其他一些意想不到的东西,我想用我们的UT来捕捉这个。并且为了不使测试过于复杂和整洁,所以我只期望验证对象的某个方法的最后一次调用,而不是验证诸如order / noMoreInteractions / AtMostTimes之类的东西。

3 个答案:

答案 0 :(得分:4)

关于调用的顺序

默认情况下,Mockito.verify()与调用顺序无关 要将其考虑在内,请将模拟包装在InOrder实例中,然后对此实例执行调用验证。

关于不再进行互动

如果在您要验证的方法之后不再调用模拟,则可以使用Mockito.verifyNoMoreInteractions(Object... mocks)检查是否有任何未经验证的交互,例如:

InOrder inOrder = Mockito.inOrder(mockedA);
inOrder.verify(mockedA).add("1");
inOrder.verify(mockedA).add("2");
Mockito.verifyNoMoreInteractions(mockedA);

如果仍然可以在要验证的方法之后调用模拟,则可以在通过传递verify(T mock, VerificationMode mode)验证调用VerificationMode之后添加,该InOrder inOrder = Mockito.inOrder(mockedA); inOrder.verify(mockedA).add("1"); inOrder.verify(mockedA).add("2"); Mockito.verify(mockedA, Mockito.atMost(2)).add(Mockito.anyString()); 检查最多执行了2次调用。

g(t)

关于您的思考和这种嘲弄方式的警告

  

由于上述测试无法捕获,如果有人意外添加另一个   在最后一次调用诸如add(“3”)。

Mockito提供了一个强大而广泛的工具包来处理模拟。一些功能,如验证,更具体地证实,没有检测到关于模拟或模拟的特定方法的更多交互使您的测试更加复杂,无法阅读和维护。 同样,目前您要检查模拟上的调用是否按特定顺序执行。但是,您通常只希望根据业务/逻辑方案而非技术调用的要求使用这些检查 例如,假设在测试方法中你有一个案例,出于商业原因,模拟方法被调用3次,另一种情况是模拟方法被调用2次。在两次预期调用的情况下,检查它是否仅被调用2次而不是更多是有意义的 但是一般来说,你应该小心谨慎,你的单元测试不会过度使用模拟验证,这可能看起来像是对流的描述的断言,而不是对行为/逻辑的断言。

答案 1 :(得分:2)

感谢@ staszko032,受ArgumentCaptor的启发,而不是getAllValues并验证序列,我们可以使用captor的getValue,因为captor的getValue总是得到最后一个真正的参数。我们可以这样做:

    ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
    Mockito.verify(mockedA, Mockito.atLeastOnce()).add(captor.capture());
    Assert.assertEquals("2", captor.getValue());

答案 2 :(得分:0)

这对我来说是你在嘲笑数据类。根据我的经验,离开(有状态的)数据类和模拟(无状态)服务会更好。这样,您可以验证测试中的方法是否生成正确的数据,而不仅仅是验证一系列调用。与testdata构建器一起(使用某种默认状态实例化数据类很容易,例如使用构建器模式),编写测试变得非常容易。

如果您确实需要模拟,那么测试所需内容的唯一方法是使用InOrder,并验证模拟上的每个调用,并以verifyNoMoreInteractions结束。