Как протестировать метод, который создает отдельный поток?

#java #multithreading #junit #junit4 #executorservice

#java #многопоточность #junit #junit4 #executorservice

Вопрос:

Это первый раз, когда я пытаюсь написать JUnit для многопоточной Java-программы.

У меня есть метод, который выглядит следующим образом, не могли бы вы, пожалуйста, подсказать, как я могу написать JUnit для этого? или указать на какие-либо подобные примеры? Заранее большое спасибо …!!

 public void myMethod(Input input) {
    if (!this.isStreamingPaused()) {
        ExecutorService publisherThreadPool = getThreadPool();
        PublisherThread publisher = new PublisherThread();
        publisher.setInputData(input);
        publisherThreadPool.execute(publisher);
        publisherThreadPool.shutdown();
    }
}

public ExecutorService getThreadPool() {
    final ThreadFactory threadFactory = new BasicThreadFactory.Builder()
                .namingPattern("MyName-%d")
                .priority(Thread.NORM_PRIORITY)
                .build();
    return Executors.newFixedThreadPool(1, threadFactory);
}
  

Комментарии:

1. Разделите свои опасения. Как следует из названия, модульные тесты должны быть нацелены на функциональные единицы. Попробуйте один тест для класса, который порождает поток, и второй тест для самого класса thread.

2. Спасибо EJK за ответ. Я собираюсь написать отдельный junit для основной функциональности в потоке PublisherThread, но меня беспокоит то, как я могу протестировать тот блок кода внутри myMethod, который генерирует поток?

3. Обратите внимание, что подобное создание пула потоков означает, что вы не сможете выполнить myMethod более одного раза. Возможно, вы также захотите проверить, был ли отключен исполнитель, а также создать новый экземпляр в этом случае.

4. Почему, publisherThreadPool.shutdown() узнав, execute что getThreadPool() возвращает один и тот же экземпляр, вы не сможете вызвать myMethod дважды, это то, что вы хотите?

5. Да, ожидается, что myMethod не будет выполняться несколько раз, пока не закончится 1 поток. Этот код написан таким образом, что только 1 поток должен публиковать данные в любое время. Если есть другая запись данных, готовая к публикации, в то время как поток уже запущен и публикует данные (одиночные или множественные данные), то он записывает данные в очередь / буфер.

Ответ №1:

Вы можете попробовать использовать java.util.concurrent.CountDownLatch

 public void myMethod(Input input) {
    if (!this.isStreamingPaused()) {
        ExecutorService publisherThreadPool = getThreadPool();

        // in case that you'd have more of the same kind of operations to do
        // you can use appropriately a higher count than 1
        CountDownLatch  latch = new CountDownLatch(1);

        PublisherThread publisher = new PublisherThread();
        publisher.setInputData(input);
        publisherThreadPool.execute(publisher);
        publisherThreadPool.shutdown();


        try {
            latch.await();
        } catch (InterruptedException e) {
            LOG.info("Interrupted by another thread");
        } 
    }
}
  

В вашем PublisherThread классе вы вносите эти изменения:

 private CountDownLatch latch;

public PublisherThread(CountDownLatch latch){
    this.latch = latch;
}

public void run(){
  try{
      // kafka business logic
      // ....
  } finally {
      // you don't want your program to hang in case of an exception 
      // in your business logic
      latch.countDown();
  }
}