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

标签 java junit

我有一个异步构建多个 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/

相关文章:

java - Junit 测试用例没有按预期工作

java - 在 eclipse 中运行 JUnit 测试会抛出 SecurityException

java - 构建测试失败,将测试标记为非强制

java - 导入 cucumber 场景

java - SimpleDateFormat 和 2013-01-17T00 :00:00-06:00

java - 将非空键和值放入哈希表时出现 NullPointerException

java - 我们可以使用JAVA列出操作系统中安装的软件吗

java - 为什么使用 AspectJ 的 google 缓存很慢,而 SpringCaching 却更快

java - 在 for 循环中使用模拟对象列表时出现 NullPointerException

java - 如果不存在则插入到表中