Как мне написать тест JUnit для тестирования потоков и событий

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

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

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

6 ответов


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

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

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

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

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

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


Это ConcurrentUnit был создан для. Использование:

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

Подробнее см. На странице ConcurrentUnit информация.


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


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

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


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

одна из трудностей тестирования потоков связана с самой их природой-они параллельны. Это означает, что вы вынуждены писать тестовый код 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();
    }
}

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


вот мое решение для тестирования метода asynchrone, который использовал поток.начало:

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();
   }
}