Избегайте тестирования параллельными нитями, когда вы можете (что большую часть времени). Это только сделает ваши тесты шероховатыми (иногда проходят, иногда терпят неудачу).
Только тогда, когда вам нужно позвонить в другую библиотеку/систему, вам, возможно, придется ждать других потоков, в этом случае всегда используйте библиотеку Awaitility вместо Thread.sleep()
.
Никогда не вызывайте в своих тестах get()
или join()
, иначе ваши тесты могут запускаться вечно на вашем сервере CI в случае, если будущее никогда не завершится. Всегда указывайте isDone()
первым в своих тестах перед вызовом get()
. Для CompletionStage, то есть .toCompletableFuture().isDone()
.
При тестировании метода нелипкая так:
public static CompletionStage<Foo> doSomething(BarService service) {
CompletionStage<Bar> future = service.getBar();
return future.thenApply(bar -> fooToBar());
}
, то вы должны не только проверить результат, передавая законченное будущее в тесте, вы также должны убедиться, что ваш метод doSomething()
не по вызову join()
или get()
. Это важно, особенно если вы используете неблокирующую структуру.
Чтобы сделать это, тест с не завершенным будущим, которые вы установили для завершения вручную:
@Test
public void testDoSomething() {
CompletableFuture<Bar> innerFuture = new CompletableFuture<>();
fooResult = doSomething(() -> innerFuture).toCompletableFuture();
assertFalse(fooResult.isDone());
// this triggers the future to complete
innerFuture.complete(new Bar());
assertTrue(fooResult.isDone());
// futher asserts about fooResult here
}
Таким образом, если добавить к future.join()
DoSomething(), тест проваливается.
Если служба использует ExecutorService, например, в thenApplyAsync(..., executorService)
, то в ваших тесты вводят однопоточный ExecutorService, например, как один из гуавы:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Если ваш код использует forkJoinPool таких как thenApplyAsync(...)
, перепишите код для использования ExecutorService (есть много веских причин) или используйте Awaitility.
Чтобы сократить пример, я сделал BarService аргументом метода, реализованным в качестве лямбды Java8 в тесте, как правило, это будет введенная ссылка, которую вы бы издевались.
Вы можете попробовать JAT (Java Asynchronous Test): https://bitbucket.org/csolar/jat – cs0lar
JAT имеет 1 наблюдателя и не обновлялся через 1,5 года. Awaitility была обновлена всего 1 месяц назад и находится на версии 1.6 на момент написания этой статьи. Я не связан ни с одним из проектов, но если бы я собирался инвестировать в дополнение к моему проекту, я бы дал больше доверия к Awaitility в это время. –
JAT до сих пор не обновляется: «Последнее обновление 2013-01-19». Просто сохраните время, чтобы перейти по ссылке. – deamon