gpt4 book ai didi

java - CompletableFuture.allOf().get() 不在单元测试中运行

转载 作者:行者123 更新时间:2023-12-02 09:29:25 34 4
gpt4 key购买 nike

我有一个异步构建多个 DTO 的方法。它在一般用途中运行良好,因此我尝试为其编写一些单元测试。该方法如下所示:

    public List<SurgeClientDto> clientLeaderboard(@RequestBody List<String> accountIds) throws ExecutionException, InterruptedException {

List<SurgeClientDto> surgeClients = new ArrayList<>(accountIds.size());

long start = System.currentTimeMillis();

List<CompletableFuture> futures = new ArrayList<>();

for (String accountId : accountIds) {
futures.add(
CompletableFuture.runAsync(() -> {
buildSurgeClientDto(surgeClients, accountId);
}, executor)
);
}

CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).get();

log.info("Time taken: {}ms", System.currentTimeMillis() - start);

return surgeClients;
}

我的测试如下:

    @Test
@DirtiesContext
public void testGetLeaderboard() throws Exception {
// Given
final List<String> accounts = new ArrayList<>();
final String accountOne = "ABCDE";
final String accountTwo = "ZYXWV";
final String accountThree = "FAKE!";
final String clientForename = "John";
final String clientSurname = "Smith";

ClientDetailsCursorResult validOne = ClientDetailsCursorResult.builder()
.accountId(accountOne)
.forename(clientForename)
.surname(clientSurname)
.build();
ClientDetailsCursorResult validTwo = ClientDetailsCursorResult.builder()
.accountId(accountTwo)
.forename(clientForename)
.surname(clientSurname)
.build();

BalanceDetailsDto validBalanceDetailsDto = new BalanceDetailsDto();
validBalanceDetailsDto.setAvailableToWithdraw(100d);
validBalanceDetailsDto.setAvailableBalance(100d);

accounts.add(accountOne);
accounts.add(accountTwo);
accounts.add(accountThree);

// When
when(accountMaintenanceRestClient.getAccount(accountOne)).thenReturn(accountDTO());
when(accountMaintenanceRestClient.getAccount(accountTwo)).thenReturn(accountDTO());
when(accountMaintenanceRestClient.getAccount(accountThree)).thenReturn(null);

when(clientDetailsJdbc.getClientAccounts(accountOne)).thenReturn(Arrays.asList(validOne));
when(clientDetailsJdbc.getClientAccounts(accountTwo)).thenReturn(Arrays.asList(validTwo));

when(balanceDetailsService.getBalanceDetails(accountOne)).thenReturn(validBalanceDetailsDto);
when(balanceDetailsService.getBalanceDetails(accountTwo)).thenReturn(validBalanceDetailsDto);

List<SurgeClientDto> surgeClientDtos = surgeParisController.clientLeaderboard(accounts);

// Then
assertThat(surgeClientDtos.get(0).getAccountId(), is(accountOne));
assertThat(surgeClientDtos.get(0).getAvailableToTrade(), is(100d));
assertThat(surgeClientDtos.get(0).getAvailableToWithdraw(), is(100d));
assertThat(surgeClientDtos.get(0).getClientName(), is(clientForename + " " + clientSurname));
}

当我运行测试时,它陷入无限循环,没有输出。当我调试代码时,要执行的最后一行是

CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).get();

我在 buildSurgeClientDto() 中放置了一个断点,并尝试再次在 Debug模式下运行,但断点从未被触发。

这是为什么呢?我需要做一些特殊的事情来测试异步CompletableFutures吗?

最佳答案

问题是你模拟了Executor。它只是从不执行任务,所以测试只是挂起。你能做的就是使用简单的执行器并将其注入(inject)到你的 Controller 中:

private Executor executor = Executors.newSingleThreadExecutor();

而不是

@Mock
private Executor executor;

对于您的测试,它应该可以工作。您不需要测试 ExecutorCompletableFuture,因为它是 JDK 的一部分并且已经经过充分测试。

但是如果你需要模拟执行器,你应该模拟或 stub :

// CompletableFuture code:
executor.execute(new AsyncRun(dep, function));

否则测试将挂起。

关于java - CompletableFuture.allOf().get() 不在单元测试中运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58101473/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com