← Назад к вопросам

Как запустить тесты параллельно в TestNG

1.3 Junior🔥 291 комментариев
#Автоматизация тестирования

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Запуск тестов параллельно в TestNG

TestNG предоставляет мощные и гибкие механизмы для параллельного выполнения тестов, что является ключевой возможностью для сокращения времени прогона тестовой suite, особенно в больших проектах. Параллелизм настраивается на разных уровнях: тесты (tests), классы (classes), методы (methods) и потоки (threads).

Основные настройки параллелизма в TestNG

Конфигурация осуществляется в файле testng.xml (или программно через объект TestNG). Основные параметры:

  • parallel: Задает режим параллельного выполнения.
  • thread-count: Определяет максимальное количество потоков для выполнения.

Пример базового testng.xml для параллельного запуска:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Parallel Suite" verbose="1" thread-count="5" parallel="tests">
    <test name="Login Tests">
        <classes>
            <class name="com.example.tests.LoginTest"/>
        </classes>
    </test>
    <test name="Search Tests">
        <classes>
            <class name="com.example.tests.SearchTest"/>
        </classes>
    </test>
</suite>

Режимы параметра parallel

  • parallel="tests": Тесты (<test> теги) внутри сьюта выполняются параллельно. В примере выше Login Tests и Search Tests запустятся одновременно. Это наиболее распространенный и безопасный уровень, так как тесты часто изолированы.
  • parallel="classes": Все классы с тестами выполняются параллельно друг другу.
  • parallel="methods": Все @Test методы выполняются параллельно. Требует особой осторожности, так как методы могут влиять на общее состояние (статические поля, синглтоны).
  • parallel="instances": Тестовые методы выполняются параллельно только в пределах одного экземпляра тестового класса, но разные экземпляры — последовательно. Полезно в комбинации с @Factory.

Пример параллелизма на уровне методов:

<suite name="Method Parallel Suite" thread-count="3" parallel="methods">
    <test name="All Tests">
        <classes>
            <class name="com.example.tests.DataDrivenTest"/>
        </classes>
    </test>
</suite>

Важные аспекты и best practices

  1. Потокобезопасность (Thread Safety): Это главный вызов при параллельном запуске.
    *   Избегайте изменения общих статических переменных.
    *   Используйте `ThreadLocal` для хранения данных, специфичных для потока (например, драйвер WebDriver в UI-тестах).
    *   Для изоляции данных в интеграционных тестах используйте уникальные идентификаторы (например, `UUID` для имен пользователей).

  1. Зависимости между тестами (dependsOnMethods, dependsOnGroups): TestNG гарантирует выполнение зависимостей, но в параллельном режиме это может привести к неожиданным задержкам или deadlock. Старайтесь минимизировать жесткие зависимости.

  2. Синхронизация через @BeforeSuite/@AfterSuite и другие аннотации конфигурации:

    *   `@BeforeSuite`/`@AfterSuite`: Выполняются **один раз** до/после всех тестов в сьюте, независимо от параллелизма.
    *   `@BeforeTest`/`@AfterTest`: Выполняются до/after каждого тега `<test>` в `testng.xml`. При `parallel="tests"` они могут выполняться в разных потоках.
    *   `@BeforeClass`/`@AfterClass`: Выполняются до/после первого/последнего тестового метода в данном классе.

  1. Управление драйвером в Selenium WebDriver: Никогда не делите один экземпляр WebDriver между потоками. Стандартный паттерн — использование ThreadLocal<WebDriver>.

    public class WebDriverHolder {
        private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();
    
        public static WebDriver getDriver() {
            if (driver.get() == null) {
                driver.set(new ChromeDriver()); // Инициализация для каждого потока
            }
            return driver.get();
        }
    
        public static void quitDriver() {
            if (driver.get() != null) {
                driver.get().quit();
                driver.remove(); // Важно: очистка ThreadLocal
            }
        }
    }
    
  2. Использование dataProvider с параллелизмом: Аннотация @DataProvider имеет параметр parallel. Установите его в true, чтобы методы, использующие этот провайдер, запускались с разными наборами данных параллельно.

    @Test(dataProvider = "userData")
    public void testLogin(String username, String password) {
        // ...
    }
    
    @DataProvider(name = "userData", parallel = true) // Данные обрабатываются параллельно
    public Object[][] provideUserData() {
        return new Object[][] {
            {"user1", "pass1"},
            {"user2", "pass2"},
            {"user3", "pass3"}
        };
    }
    

Динамическая настройка через код

Вы можете программно создать и запустить suite:

TestNG testng = new TestNG();
XmlSuite suite = new XmlSuite();
suite.setName("Dynamic Parallel Suite");
suite.setParallel(ParallelMode.METHODS);
suite.setThreadCount(4);

XmlTest test = new XmlTest(suite);
test.setName("Dynamic Test");
List<XmlClass> classes = new ArrayList<>();
classes.add(new XmlClass("com.example.tests.MyTestClass"));
test.setXmlClasses(classes);

List<XmlSuite> suites = new ArrayList<>();
suites.add(suite);
testng.setXmlSuites(suites);
testng.run();

Заключение

Для эффективного использования параллелизма в TestNG:

  • Начинайте с уровня parallel="tests" для изоляции функциональных групп.
  • Тщательно проектируйте тесты как независимые и идемпотентные.
  • Используйте ThreadLocal для изоляции состояния.
  • Рассчитывайте thread-count исходя из возможностей целевой системы (CPU, память, лимиты внешних систем).
  • Помните, что параллельный запуск не отменяет необходимости в качественной, предсказуемой и стабильной тестовой среде.