Singleton WebDriver (Singleton WebDriver)

Один экземпляр WebDriver создаётся как статический синглтон и используется всеми тестами в JVM. Браузерная сессия никогда не пересоздаётся между тестами.

Симптомы

  • Статическое поле private static WebDriver driver в базовом классе или утилите
  • Метод getDriver() с паттерном «ленивая инициализация» через if (driver == null)
  • Один экземпляр ChromeDriver/FirefoxDriver на весь тест-ран
  • @BeforeAll static void setUp() с созданием одного driver для всего класса

Причины возникновения

  • Создание WebDriver кажется «дорогим» — синглтон экономит время запуска
  • Паттерн синглтона знаком из продакшн-кода и переносится в тесты без адаптации
  • Нет понимания жизненного цикла браузерной сессии и изоляции тестов
  • Первый рабочий прототип использовал статическое поле, и никто его не рефакторил

Почему это проблема

  • Нельзя запускать параллельно: несколько потоков используют один driver → гонки, случайные падения
  • Накопление состояния: cookies, localStorage, открытые диалоги от теста A влияют на тест B
  • Утечки сессий: если тест упал раньше quit() — driver завис, процесс браузера не завершён
  • Один браузер: нельзя тестировать разные профили, языки или разрешения экрана одновременно
  • Сложная очистка: нужно помнить, что именно «замусорил» предыдущий тест

Решение

ThreadLocal<WebDriver> — каждый поток получает свой driver:

// ❌
public static WebDriver getDriver() {
    if (driver == null) driver = new ChromeDriver();
    return driver;
}

// ✅
private static final ThreadLocal<WebDriver> driverHolder = new ThreadLocal<>();

public static WebDriver getDriver() { return driverHolder.get(); }
public static void initDriver()  { driverHolder.set(new ChromeDriver()); }
public static void quitDriver()  {
    driverHolder.get().quit();
    driverHolder.remove();
}