QA Interview Hub · База знань · Тести
Selenium + Java
Фреймворк і запуски
JUnit 5 проти TestNG
Selenium лише керує браузером; запускає тести, готує дані й збирає звіти тестовий фреймворк. Два поширені в Java: JUnit 5 і TestNG.
| JUnit 5 | TestNG |
| Підготовка/завершення | @BeforeEach, @AfterEach, @BeforeAll, @AfterAll (static, якщо немає PER_CLASS) | @BeforeMethod, @AfterMethod, @BeforeClass, @BeforeSuite, @BeforeTest |
| Параметризація | @ParameterizedTest + @ValueSource, @CsvSource, @MethodSource | @DataProvider (можна parallel = true) |
| Групування | @Tag + фільтри в збірці | groups, testng.xml |
| Залежності тестів | свідомо немає (тести мають бути незалежними) | dependsOnMethods, dependsOnGroups |
| Розширення | модель Extension API (@ExtendWith, TestWatcher, ParameterResolver) | слухачі (ITestListener, IRetryAnalyzer) |
| Паралельність | junit-platform.properties | атрибути parallel і thread-count у testng.xml |
@ParameterizedTest
@CsvSource({"admin,Admin panel", "guest,Welcome"})
void showsRoleHome(String role, String heading) {
// ...
}
Нові проєкти найчастіше беруть JUnit Jupiter (JUnit 5, тепер JUnit 6 з тим самим API): ширша екосистема, інтеграція з IDE та збіркою, зручні розширення. TestNG лишається у великих існуючих наборах, де потрібні групи, залежності й вбудований testng.xml. У JUnit 5 немає вбудованого retry: його додають розширенням або повтором упалих тестів на рівні Surefire чи CI.
Кожен тест має створювати власний стан і не залежати від порядку: це перша умова паралельного запуску.
Selenium Grid 4 і Docker: як влаштований і як запускати
Selenium Grid маршрутизує команди клієнта на віддалені браузери: паралельні запуски на багатьох машинах, різні версії браузерів і ОС. Тест підключається через RemoteWebDriver до одного URL (типово порт 4444), а решту робить Grid.
Три режими розгортання Grid 4:
- Standalone — усе в одному процесі; найпростіше для розробки й малих наборів;
- Hub and Node — один Hub і кілька Node (кожен із власними браузерами, можливо різні ОС);
- Distributed — компоненти окремими процесами для великого масштабу.
Компоненти Grid 4: Router (приймає запити, спрямовує їх), Distributor (знаходить вільний слот на Node), Session Map (хто з сесій на якому Node), New Session Queue (черга запитів на нові сесії, коли слотів немає), Node (запускає браузери), Event Bus (обмін подіями між компонентами). Стан видно на /status і в UI на /ui.
Docker. Готові образи selenium/standalone-chrome, selenium/standalone-firefox, selenium/hub + node-chrome дають браузер без встановлення на машину.
docker run -d -p 4444:4444 -p 7900:7900 --shm-size="2g" selenium/standalone-chrome
--shm-size (або /dev/shm) потрібен, бо Chrome активно користується спільною пам’яттю; з малим обсягом браузер падає на важких сторінках;
- порт 7900 — перегляд сесії через noVNC у браузері, зручно для дебагу;
- за замовчуванням контейнер виконує одну сесію (
SE_NODE_MAX_SESSIONS); більше дозволяє ця змінна, але межу задають ресурси контейнера.
У CI зазвичай піднімають Grid як сервіс (Docker Compose чи сервіс-контейнер джоби), чекають готовності на /status і запускають тести з URL Grid. Для завантаження файлів на віддалену машину потрібен LocalFileDetector.
Паралельні запуски: драйвер на потік, ізоляція, CI
WebDriver не потокобезпечний: одну сесію не можна ділити між потоками. Правило паралелізму: один драйвер на тест (потік), створений перед тестом і закритий після нього.
Типова пастка — static WebDriver driver у базовому класі або Page Object: паралельні потоки перезаписують одне посилання й керують чужим браузером. Рішення:
- створювати драйвер у
@BeforeEach (JUnit) / @BeforeMethod (TestNG) і передавати в Page Object через конструктор;
- або тримати його в
ThreadLocal<WebDriver> — тоді кожен потік бачить свій екземпляр, а remove() після тесту запобігає витоку;
- у JUnit 5 зручно оформити драйвер як розширення з
ParameterResolver, що створює й закриває його.
private static final ThreadLocal<WebDriver> DRIVER = new ThreadLocal<>();
static WebDriver driver() { return DRIVER.get(); }
@BeforeEach void start() { DRIVER.set(new ChromeDriver()); }
@AfterEach void stop() { DRIVER.get().quit(); DRIVER.remove(); }
Вмикання паралельності: у JUnit 5 — junit.jupiter.execution.parallel.enabled=true і mode.default=concurrent у junit-platform.properties; у TestNG — parallel="methods" (або classes, tests) і thread-count у testng.xml.
Паралельність вимагає ізоляції даних: тести не діляться акаунтами, замовленнями, файлами. Інакше з’являються флейки, які не відтворюються поодинці. Кількість потоків узгоджують із ресурсами Grid або CI-раннера.
У CI: headless або Grid у контейнері, кеш Selenium Manager між запусками, артефакти (скриншоти, логи, звіт) зберігаються навіть для упалих джоб, повторний запуск лише упалих тестів позначають у звіті як flaky, а не приховують.