Mockito doAnswer when 被调用时的方法以外的方法

时间:2021-05-05 19:09:17

标签: java exception mockito reset

在我们的一个测试套件中,我们正在模拟一个间谍的方法。

@SpyBean(name="myFutureList")
@Autowired
List<CompletableFuture<Void>> myFutureList;

....

doAnswer(invocation -> {
    CompletableFuture<Void> future = invocation.getArgument(0);
    future.get();
    invocation.callRealMethod();
    return true;
}).when(myFutureList).add(any());

....

clearInvocations(myFutureList);

大部分有效,但是当测试套件出现延迟时会抛出异常。调查这些异常似乎是在 myFutureList.isEmpty()myFutureList.stream() 调用模拟方法时发生的问题。即在这种情况下

CompletableFuture<Void> future = invocation.getArgument(0);

java.lang.ArrayIndexOutOfBoundsException 异常而爆炸。

但是这个方法只能在调用 .when(myFutureList).add(any()); 时调用。

为什么会发生这种情况?

1 个答案:

答案 0 :(得分:0)

我花了一整天来调试这个问题。但根本原因是 Mockito 中的线程错误。我提出了一个问题,描述了针对他们的回购的问题

https://github.com/mockito/mockito/issues/2289

简而言之

public StubbedInvocationMatcher addAnswer(Answer answer, boolean isConsecutive, Strictness stubbingStrictness) {
    Invocation invocation = this.invocationForStubbing.getInvocation(); <--- Here
    ThreadSafeMockingProgress.mockingProgress().stubbingCompleted();
    if (answer instanceof ValidableAnswer) {
        ((ValidableAnswer)answer).validateFor(invocation);
    }

    synchronized(this.stubbed) {
        if (isConsecutive) {
            ((StubbedInvocationMatcher)this.stubbed.getFirst()).addAnswer(answer);
        } else {
            Strictness effectiveStrictness = stubbingStrictness != null ? stubbingStrictness : this.mockStrictness;
            <-- Here -->
            this.stubbed.addFirst(new StubbedInvocationMatcher(answer, this.invocationForStubbing, effectiveStrictness)); 
        }

        return (StubbedInvocationMatcher)this.stubbed.getFirst();
    }
}

这里局部变量invocation反对localConsumerTaskList.add(null),而类变量this.invocationForStubbing反对localConsumerTaskList.isEmpty()。这导致针对 isEmpty() 调用注册存根方法。当线程在 synchronized 代码运行之前更新类变量时会发生这种情况。

相关问题