CompletableFuture.allOf (). Get () не запускается в модульном тесте - PullRequest
0 голосов
/ 25 сентября 2019

У меня есть метод, который асинхронно создает несколько 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() и попытался снова запустить в режиме отладки, но точка останова никогда не срабатывает.

Почему это?Что-то особенное, что я должен сделать, чтобы проверить асинхронность CompletableFutures?

1 Ответ

0 голосов
/ 27 сентября 2019

Проблема в том, что вы издеваетесь Executor.Он просто никогда не выполняет задачу, поэтому тест просто зависает.Что вы можете сделать, это просто использовать простой executor и вставить его в свой контроллер:

private Executor executor = Executors.newSingleThreadExecutor();

вместо

@Mock
private Executor executor;

Для вашего теста это должно работать.Вам не нужно тестировать Executor и CompletableFuture, потому что он является частью JDK и хорошо протестирован alredy.

Но если вам нужен фиктивный исполнитель, вы должны смутить или заглушить:

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

в противном случае тест будет зависать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...