Как написать тестовый пример JUnit для тестирования потоков и событий - PullRequest
9 голосов
/ 17 марта 2011

У меня есть Java-код, который работает в одном (основном) потоке. Из основного потока я создаю новый поток, в котором я делаю серверный вызов. После завершения вызова сервера я выполняю некоторую работу в новом потоке, после чего код присоединяется к основному потоку.

Я использую задания Eclipse для вызова сервера.

Я хочу знать, как мне написать тестовый пример JUnit для этого.

Ответы [ 6 ]

9 голосов
/ 17 марта 2011

Вам может потребоваться реструктурировать ваш код, чтобы его можно было легко протестировать.

Я вижу несколько отдельных областей для тестирования:

  1. Код управления потоками: код, который запускаетсяпоток (ы) и, возможно, ожидает результатов
  2. Код "работника" выполняется в потоке
  3. Проблемы параллелизма, которые могут возникнуть, когда активны несколько потоков

Структурируйте свою реализацию так, чтобы код управления потоками не зависел от деталей работника.Затем вы можете использовать Mock Workers для включения тестирования управления потоками - например, Mock Worker, который не удается определенным образом, позволяет вам тестировать определенные пути в коде управления.

Реализуйте код Worker, чтобы его можно было запуститьв изоляции.Затем вы можете выполнить это модульное тестирование независимо, используя макеты для сервера.

Для параллельного тестирования помогут ссылки, предоставленные Abhijeet Kashnia.

5 голосов
/ 21 июня 2011

Это то, для чего ConcurrentUnit был создан.Общее использование:

  1. порождение некоторых потоков
  2. ожидание или ожидание основного потока
  3. выполнение утверждений из рабочих потоков (которые через ConcurrentUnit сообщаютсявернуться к основному потоку)
  4. Возобновить основной поток из одного из рабочих потоков после завершения всех утверждений

Для получения дополнительной информации см. страницу ConcurrentUnit.

2 голосов
/ 17 марта 2011

Я предполагаю, что вы, возможно, выполнили свой макет-код и, возможно, захотите простой интеграционный тест, чтобы убедиться, что ваш серверный вызов работает.

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

Например, ваш код может выглядеть примерно так:

@Test
public void myIntegrationTest() throws Exception {

   // Setup your test


   // call your threading code
   Results result = myServerClient.doThreadedCode();

   // Wait for your code to complete
   sleep(5);

   // Test the results
   assertEquals("some value",result.getSomeValue());

}


private void sleep(int seconds) {

    try {
        TimeUnit.SECONDS.sleep(seconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

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

2 голосов
/ 17 марта 2011

Ресурсы, предоставленные Абхиджит Кашния , могут помочь, но я не уверен, чего вы пытаетесь достичь.

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

2 голосов
/ 17 марта 2011

Я предлагаю вам использовать фальшивый фреймворк, чтобы подтвердить, что серверный вызов действительно был сделан. Что касается модульного тестирования потоков: Модульное тестирование многопоточных приложений

0 голосов
/ 16 сентября 2016

Вот мое решение для тестирования асинхронного метода, который использовал thread.start:

public class MyClass {      
   public void doSomthingAsynchrone() {
      new Thread(() -> {
         doSomthing();
      }).start();
   }

   private void doSomthing() {
   }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClass.class)
public class MyClassTest {
   ArgumentCaptor<Runnable> runnables = ArgumentCaptor.forClass(Runnable.class);

   @InjectMocks
   private MyClass myClass;

   @Test
   public void shouldDoSomthingAsynchrone() throws Exception {  

      // create a mock for Thread.class
      Thread mock = Mockito.mock(Thread.class);

      // mock the 'new Thread', return the mock and capture the given runnable
      whenNew(Thread.class).withParameterTypes(Runnable.class)
            .withArguments(runnables.capture()).thenReturn(mock);

      myClass.doSomthingAsynchrone();

      runnables.getValue().run();

      /**
       *  instead of 'runnables.getValue().run();' you can use a real thread.start
       *
       *   MockRepository.remove(Thread.class);
       *   Thread thread = new Thread(runnables.getValue());
       *   thread.start();
       *   thread.join();
       **/

      verify(myClass, times(1)).doSomthing();
   }
}
...