为什么 mockito 会触发验证两次?

Why mockito will trigger the verify twice?

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

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 调用耗尽。

我不会说这是“设计使然”,而是说这是当前实现所做的。执行断言的 Mockito Times class 具有以下方法(我使用的是最新版本,所以 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);

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