Многопоточность

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

TestNG

public class ConcurrencyTest extends Assert {
  private Map<String, String> data;

  @BeforeClass
  void setUp() throws Exception {
    data = new HashMap<String, String>();
  }

  @AfterClass
  void tearDown() throws Exception {
    data = null;
  }

  @Test(threadPoolSize = 30, invocationCount = 100, invocationTimeOut = 10000)
  public void testMapOperations() throws Exception {
    data.put("1", "111");
    data.put("2", "111");
    data.put("3", "111");
    data.put("4", "111");
    data.put("5", "111");
    data.put("6", "111");
    data.put("7", "111");
    for (Map.Entry<String, String> entry : data.entrySet()) {
      System.out.println(entry);
    }
    data.clear();
  }

  @Test(singleThreaded = true, invocationCount = 100, invocationTimeOut = 10000)
  public void testMapOperationsSafe() throws Exception {
    data.put("1", "111");
    data.put("2", "111");
    data.put("3", "111");
    data.put("4", "111");
    data.put("5", "111");
    data.put("6", "111");
    data.put("7", "111");
    for (Map.Entry<String, String> entry : data.entrySet()) {
      System.out.println(entry);
    }
    data.clear();
  }
}

Свойства:

  • threadPoolSize определяет максимальное количество потоков используемое для тестов;

  • singleThreaded если установлен в true все тесты будут запущены в одном потоке;

  • invocationCount определяет количество запусков теста;

  • invocationTimeOut определяет общее время всех запусков теста, после которого тест считается провалившемся.

Первый тест будет время от времени проваливаться с ConcurrentModificationException, так как будет запускаться из разных потоков, второй — нет, так как все тесты будут запущены последовательно из одного потока.

Еще можно установить параметр parallel у дата провайдера в true, тогда тесты для каждого набора данных будут запущены паралельно, в отдельном потоке:

public class ConcurrencyTest extends Assert {
  // some staff here

  @DataProvider(parallel = true)
  public Object[][] concurrencyData() {
    return new Object[][] {
      {"1", "2"},
      {"3", "4"},
      {"5", "6"},
      {"7", "8"},
      {"9", "10"},
      {"11", "12"},
      {"13", "14"},
      {"15", "16"},
      {"17", "18"},
      {"19", "20"},
    };
  }

  @Test(dataProvider = "concurrencyData")
  public void testParallelData(String first, String second) {
    final Thread thread = Thread.currentThread();
    System.out.printf("#%d %s: %s : %s", thread.getId(), thread.getName(), first, second);
    System.out.println();
  }
}

JUnit В JUnit сконфигурировать параллельный запуск тестов можно с помощью ParallelComputer класса:

public class ParallelComputerTest {  

   @Test  
   public void test() {      
      Class[] cls={ParallelTest1.class,ParallelTest2.class };  

      //Parallel among classes  
      JUnitCore.runClasses(ParallelComputer.classes(), cls);  

      //Parallel among methods in a class  
      JUnitCore.runClasses(ParallelComputer.methods(), cls);  

      //Parallel all methods in all classes  
      JUnitCore.runClasses(new ParallelComputer(true, true), cls);     
   } 

   public static class ParallelTest1 {  
      @Test 
      public void a(){} 

      @Test 
      public void b(){}  
   }  

   public static class ParallelTest2 {  
      @Test 
      public void a(){} 

      @Test 
      public void b(){}  
   }  
}

Параллельный запуск тестов - это очень полезная опция. Однако чаще всего лучще ее использовать из билд инструмента.

Задание 1. Для TestNG напишите тест с ожидаением внутри 3 сек, сконфигурируйте на запуск 3 раза. Попробуйте запустить его в одном потоке, а затем в 3. Сравните время выполнения.

Задание 2. Сделайте тоже самое для JUnit.

Last updated