在我的类中,我有一个类字段,我正在验证该类字段的方法被调用三次。现在我将逻辑移至“CompletableFuture.sypplyAsync”方法,它不再起作用: 我的测试失败了,它说它不会被调用,这正是我所期望的。
我的班级:
import org.camunda.bpm.engine.RuntimeService;
public class StartProcessService {
private final RuntimeService runtimeService;
public void handleInExkassodatenRequest(MyRequest request) {
request.getDaten().forEach(entity -> {
CompletableFuture.supplyAsync(() -> selectRequiredProcess(entity))
.thenAccept(caseId -> {
log.info("Case started ");
})
.exceptionally(err -> {
return null;
});
});
}
private CompletableFuture<String> selectRequiredProcess(InExkassodaten entity) {
startNewProcess(entity);
return CompletableFuture.completedFuture(entity.getCaseId());
}
private void startNewProcess(MyObject myObject) {
ProcessInstance processInstance = runtimeService
.createProcessInstanceByKey("MY_KEY")
.setVariable("MY_VAR", myObject)
.execute();
}
}
我的旧测试方法如下所示:
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class MyServiceTest {
@InjectMocks
private StartProcessService startProcessService;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private RuntimeService runtimeService;
@Test
void startProcesses() {
ProcessInstantiationBuilder processInstanceByKey = mock(ProcessInstantiationBuilderImpl.class);
when(runtimeService.createProcessInstanceByKey(anyString())).thenReturn(processInstanceByKey);
when(processInstanceByKey.setVariable(anyString(), any())).thenReturn(processInstanceByKey);
when(processInstanceByKey.execute()).thenReturn(mock(ProcessInstance.class));
startProcessService.handleInExkassodatenRequest(InExkassodatenFactory.createValidTestData());
verify(runtimeService, times(3)).createProcessInstanceByKey(anyString());
}
之前检查了是否调用了runtimeService.createProcessInstanceByKey。 但是随着 CompletableFutur.supplyAsync 的引入失败,并进入“异常”错误:
需要但未调用:runtimeService.createProcessInstanceByKey( ); -> 在 实际上,与这个mock.StartProcessServiceTest.startProcesses(StartProcessServiceTest.java:52)的交互为零
我需要如何重新设计我的生产代码或测试代码才能使用 CompleableFuture 进行测试?
supplyAsync
正如其名称所示:它异步运行代码。它不保证代码块将在when被执行。
我看到两个明显的修复:
supplyAsync
采用可选的 Executor
参数。默认是在 ForkJoinPool.commonPool
上执行,但您可以传递任何其他执行器。一种可能的执行器值是 Runnable::run
,它将直接执行代码,而不将其分派到线程池(因此代码保持单线程)。您可以扩展您的类以拥有执行程序字段或属性,并在测试中将 Runnable::run
分配给该字段。
Awaitility
重新运行断言,直到达到给定超时。类似于await().untilAsserted(() -> verify(yourMock, times(3)).yourCall())
。
我建议第一种方法,因为它消除了多线程的复杂性并使事情变得简单。