JUnit завершает дочерние потоки
Когда я проверяю выполнение метода, который создает дочерний поток, тест JUnit заканчивается перед дочерним потоком и убивает его.
Как заставить JUnit ждать завершения дочернего потока?
Спасибо
Ответы
Ответ 1
После прочтения вопроса и некоторых комментариев кажется, что вам нужна методика для асинхронных операций модульного тестирования. doSomething() возвращается немедленно, но вы хотите, чтобы тестовый код дождался его завершения, а затем выполните некоторые проверки.
Проблема в том, что тест не знает о том, что потоки порождаются вызовом, поэтому, видимо, у него нет средств ждать их. Можно подумать о многих сложных (и, вероятно, ошибочных) способах решения этого вопроса, но, на мой взгляд, здесь существует проблема дизайна. A unit test должен имитировать клиента некоторого API, и он не должен ничего принимать в отношении реализации; Он должен только проверять функциональность, как это отражено в API и его документации. Поэтому я бы не пытался обнаруживать и отслеживать потоки, созданные асинхронным вызовом. Вместо этого я бы улучшил API тестируемого класса, если это необходимо. Класс, к которому принадлежит асинхронный вызов, должен предоставить некоторый механизм для обнаружения завершения. Я могу думать о 3 способах, но, вероятно, есть больше:
1) Разрешить регистрацию слушателя, который получает уведомление после завершения операции
2) Предоставление синхронной версии операции. Реализация может вызывать асинхронную версию, а затем блокировать до завершения. Если класс не должен раскрывать такой метод, его видимость может быть уменьшена до защищенного пакета, чтобы тест мог получить к нему доступ.
3) Используя шаблон wait-notify, на каком-либо видимом объекте.
Если класс не предоставляет такого механизма, то он не может быть проверен, и, что еще хуже, он, вероятно, тоже не может быть повторно использован.
Ответ 2
Попробуйте использовать thread.join() в созданном потоке. Это будет ждать, пока этот поток не умрет.
Изменить: чтобы избежать этого, попробуйте Thread.getThreadGroup().setDaemon(true);
в тесте или, возможно, в методе setUp()
. Я не тестировал это, хотя.
Группа потоков демона автоматически уничтожается, когда последний поток остановлен или уничтожена его последняя группа потоков.
Интересно, вызывает ли JUnit System.exit()
или что-то, как только тест заканчивается.
Ответ 3
Основной метод, который обозначил @Eyal, - это ConcurrentUnit. Общее использование:
- Создайте несколько потоков
- Ожидание или спуск основного потока
- Выполнять утверждения из рабочих потоков (которые через ConcurrentUnit возвращаются в основной поток)
- Возобновить основной поток из одного из рабочих потоков после завершения всех утверждений
Дополнительную информацию см. на странице ConcurrentUnit.
Ответ 4
Возможно, группируйте свои потоки с помощью ExecutorService, затем используйте shutdown и awaitTermination метод?
Условие состоит в том, чтобы использовать Runnable или Future, а не сами темы.
Ответ 5
while (s.isRunning()) {
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Вы можете попытаться заблокировать поток JUnit и дождаться завершения потока. Thread.sleep()
необходим, чтобы ваш поток не зависал CPU. В этом примере s будет вашим потоком, вам нужно будет иметь метод isRunning()
, чтобы вы могли проверить, работает ли поток все SLEEP_TIME
миллисекунды. Я знаю, что это не самое лучшее решение, но если у вас есть только 2 потока, и вы не хотите, чтобы JUnit убивал вашу нить, это работает. Цикл while заставляет этот поток JUnit оставаться в живых и ждать завершения вашего другого потока.