Как выполнять тесты параллельно TestNG/JUnit?qa-66

Параллельное выполнение тестов значительно сокращает время прогона тестовой suite. Рассмотрим подходы для обоих фреймворков.

1. Параллелизм в TestNG

1.1 Конфигурация через testng.xml

Основной способ настройки параллельного выполнения:

<suite name="Parallel Suite" parallel="methods" thread-count="5">
    <test name="Test Group" parallel="classes" thread-count="3">
        <classes>
            <class name="com.example.Test1"/>
            <class name="com.example.Test2"/>
        </classes>
    </test>
</suite>

Уровни параллелизма:

  • methods: параллельное выполнение методов
  • tests: параллельное выполнение тестовых блоков <test>
  • classes: параллельное выполнение классов
  • instances: параллельное выполнение экземпляров тестового класса

1.2 Аннотации для управления потоками

@Test(threadPoolSize = 3, invocationCount = 10)
public void concurrentTest() {
    // Тест выполнится 10 раз в 3 потоках
}

2. Параллелизм в JUnit 5

2.1 Активация в свойствах

Добавьте в junit-platform.properties:

junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.config.fixed.parallelism=4

2.2 Управление на уровне тестов

import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;

@Execution(ExecutionMode.CONCURRENT)
class ParallelTestClass {
    // Все тесты будут выполняться параллельно
}

3. Ключевые различия

Особенность TestNG JUnit 5
Конфигурация XML-файл .properties файл
Гранулярность Методы/Классы/Тесты Классы/Методы
Управление потоками threadPoolSize Параллелизм через стратегии
Встроенная поддержка Полная Требует активации

4. Лучшие практики параллельного выполнения

  1. Изоляция тестов:

    • Не используйте общее состояние между тестами
    • Для Selenium создавайте отдельные драйверы для каждого потока
  2. Управление ресурсами:

    @BeforeMethod
    public void setup() {
        // Инициализация для каждого потока
    }
    
  3. Синхронизация доступа:

    • Для общих ресурсов используйте synchronized или ThreadLocal
    • Пример для Selenium:
      private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();
      
  4. Балансировка нагрузки:

    • Оптимальное количество потоков = количество ядер CPU × 1.5

5. Решение распространенных проблем

Проблема: Состояние гонки (race conditions)
Решение: Используйте @BeforeMethod вместо @BeforeClass для инициализации

Проблема: Нестабильные тесты
Решение: Добавьте повторный запуск для упавших тестов:

<!-- Для TestNG -->
<test name="FlakyTests">
    <classes>
        <class name="com.example.FlakyTests">
            <methods>
                <include name="unstableTest" invocation-count="3"/>
            </methods>
        </class>
    </classes>
</test>

6. Интеграция с CI/CD

Для Jenkins добавьте параметр параллельного выполнения:

pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                sh 'mvn test -Dparallel=methods -DthreadCount=4'
            }
        }
    }
}

Резюмируем:

TestNG предоставляет более гибкие настройки параллелизма через XML-конфигурацию, в то время как JUnit 5 требует явной активации через properties-файл. Оба фреймворка эффективно ускоряют выполнение тестов при правильной настройке изоляции тестовых данных.