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 оставаться в живых и ждать завершения вашего другого потока.