【问题标题】:Why mockito will trigger the verify twice?为什么 mockito 会触发两次验证?
【发布时间】:2021-01-06 18:21:32
【问题描述】:

我在以下测试中注意到了这个问题:

verify(mockedObject).functionCall(argThat(inputStream -> {
    final String content = ... // read the inputStream
    assertEquals(expectedContent, content);
    return true;
}));

尽管assertEquals 断言是真的,它实际上会失败。我调试测试,发现lambda函数到达了两次,第二次流的光标在流的末尾。这就是它失败的原因。

所以我必须先重置流:

verify(mockedObject).functionCall(argThat(inputStream -> {
    inputStream.reset();
    final String content = ... // read the inputStream
    assertEquals(expectedContent, content);
    return true;
}));

问题是,为什么 lambda 会被触发两次?这是设计使然吗?有文件吗?

Mockito 版本:2.22

Junit 版本:5.6.0

Java 版本:1.8

更新

该方法只调用一次,两次 lambda 调用的输入是完全相同的输入。实际上,它们是同一个对象。我唯一要做的就是重置流,因为它已被第一次 lambda 调用耗尽。

【问题讨论】:

  • 完全随机猜测:你调用了多少mockedObject的方法?是否有可能第二次调用方法是没有参数的?
  • @Pelocho 一次,否则整个验证会失败,对吧? verify(mockedObject)verify(mockedObject, times(1)) 的别名。
  • @Sraw times(1) 考虑到您在argThat 中执行的匹配。如果使用不同的输入调用了两次并且只有一个匹配,则验证成功。
  • @ttzn 谢谢,我可以确保两件事。首先,该方法只被调用一次。其次,同一输入触发了 lambda 两次,当我到达第二个 lambda 调用时,inputStream 与第一个完全相同。我将在问题中更新此信息。

标签: java mockito junit5


【解决方案1】:

我不会说这是“设计使然”,而是说它是当前实现所做的。执行您的断言的 Mockito Times 类具有以下方法(我使用的是最新版本,所以 YMMV):

public void verify(VerificationData data) {
    List<Invocation> invocations = data.getAllInvocations();
    MatchableInvocation wanted = data.getTarget();

    if (wantedCount > 0) {
        checkMissingInvocation(data.getAllInvocations(), data.getTarget());
    }
    checkNumberOfInvocations(invocations, wanted, wantedCount);
}

checkMissingInvocationcheckNumberOfInvocations 都对所有调用列表执行独立过滤以保留相关调用,因此您声明的任何匹配器最终都会为每次调用执行两次。这实际上是完全相同的调用:

List<Invocation> actualInvocations = findInvocations(invocations, wanted);

也许过滤后的列表可以被缓存,但关键是除非文档中另有说明,否则您不能假设您提供的函数只会执行一次。此外,谓词函数通常不会产生副作用。

【讨论】:

  • 匹配器应该是幂等的。感谢您深入研究源代码,按照您的路径,我找到了提供该行为的相同源代码。嗯,我认为无论如何都应该记录下来。
猜你喜欢
  • 1970-01-01
  • 2017-01-08
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 2021-07-08
  • 2014-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多