Тестирование CompletableFuture.allOf. присоединение длится вечно - PullRequest
0 голосов
/ 31 марта 2020

Я пытаюсь проверить метод, который использует CompletableFuture.allOf. Я фальсифицирую фьючерсы, чтобы они возвращали необходимое значение при соединении. по какой-то причине, которую я не могу понять. join () результата занимает вечность. любая помощь будет делать!

Заранее спасибо.

    @Mock private CompletableFuture<String> future1; // for sequence test
    @Mock private CompletableFuture<String> future2; // for sequence test
    @Mock private CompletableFuture<String> future3; // for sequence test

    private BBService bbServiceTest;

    @Test
    public void testSequence() {
        final String[] expectedResults = {"res1", "res2", "res3"};
        List<CompletableFuture<String>> futures = new Vector<>();

        when(future1.join()).thenReturn(expectedResults[0]);
        when(future2.join()).thenReturn(expectedResults[1]);
        when(future3.join()).thenReturn(expectedResults[2]);

        futures.add(future1);
        futures.add(future2);
        futures.add(future3);

        bbServiceTest.sequence(futures).join();
        Assert.assertTrue(future1.isDone());
        Assert.assertTrue(future2.isDone());
        Assert.assertTrue(future3.isDone());

//        for (int i = 0; i < actualResults.size(); i++) {
//            Assert.assertEquals(expectedResults[i], actualResults.get(i));
//        }
    }


метод последовательности внутри BBService:

    public <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futuresList) {
        return CompletableFuture
                .allOf(futuresList.toArray(new CompletableFuture[0])) // (1)
                .thenApply(v ->
                        futuresList.stream()
                                .map(CompletableFuture::join)
                                .collect(Collectors.toList())
                );
    }

1 Ответ

3 голосов
/ 31 марта 2020

Это потому, что ваш futures никогда не будет завершен. CompletableFuture.allOf возвращает новое CompletableFuture, которое завершается, когда все заданные CompletableFutures завершены.

future1.complete(), future2.complete() и future3.complete() никогда не будут вызваны.

CompletableFuture.join() возвращает результат, если будущее завершено. Поскольку вы высмеиваете фьючерсы в своем коде, они возвращают строки, определенные в expectedResults для join, даже если они не завершены. Но это именно проблема. Они не завершены. Вот почему тест не заканчивается sh.

Я немного скорректировал ваш тестовый класс, чтобы продемонстрировать, как он работает:

public class FutureTest {
    @Test
    public void testSequence1() {
        List<CompletableFuture<String>> futures = getFutures();
        CompletableFuture<Void> myCombinedFuture = sequence(futures);
        // here we complete each future
        futures.forEach(future -> future.complete("future-completed"));
        myCombinedFuture.join();

        // this works because we completed all futures before
        Assert.assertTrue(myCombinedFuture.isDone());
    }

    @Test
    public void testSequence2() {
        List<CompletableFuture<String>> futures = getFutures();
        CompletableFuture<Void> myCombinedFuture = sequence(futures);
        futures.get(0).complete("completed-future1");
        futures.get(1).complete("completed-future2");

        myCombinedFuture.join();
        // this does not work because future3 is not completed -> we wait forever
        Assert.assertTrue(myCombinedFuture.isDone());
    }

    @Test
    public void testSequence3() {
        List<CompletableFuture<String>> futures = getFutures();
        CompletableFuture<Void> myCombinedFuture = sequence(futures);
        futures.get(0).complete("completed-future1");
        futures.get(1).complete("completed-future2");

        // complete future 3 asynchronous after 2 seconds
        futures.get(2).completeAsync(() -> {
            // wait for 2 seconds
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return "completed-future3";
        });

        myCombinedFuture.join();
        // after 2 seconds all futures are completed and the test will pass
        Assert.assertTrue(myCombinedFuture.isDone());
    }

    public CompletableFuture<Void> sequence(
            List<CompletableFuture<String>> futuresList) {
        return CompletableFuture.allOf(
            futuresList.toArray(new CompletableFuture[0]));
    }

    public List<CompletableFuture<String>> getFutures() {
        return List.of(
                new CompletableFuture<>(),
                new CompletableFuture<>(),
                new CompletableFuture<>()
        );
    }
}
...