在我们的一个测试套件中,我们正在模拟一个间谍的方法。
@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());
时调用。
为什么会发生这种情况?
答案 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
代码运行之前更新类变量时会发生这种情况。