Какие паттерны проектирования, помимо Page Object Model, ты знаешь и используешь в автотестах?

«Какие паттерны проектирования, помимо Page Object Model, ты знаешь и используешь в автотестах?» — вопрос из категории Паттерны проектирования, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Помимо Page Object Model (POM), в построении поддерживаемых и масштабируемых автотестов я активно применяю следующие паттерны:

1. Factory Method / Abstract Factory: Использую для создания экземпляров драйверов или сложных объектов данных. Это позволяет легко переключаться между браузерами или окружениями.

public class DriverFactory {
    public static WebDriver createDriver(String browserName) {
        switch (browserName.toLowerCase()) {
            case "chrome":
                WebDriverManager.chromedriver().setup();
                return new ChromeDriver();
            case "firefox":
                WebDriverManager.firefoxdriver().setup();
                return new FirefoxDriver();
            case "remote":
                return new RemoteWebDriver(new URL("http://grid-hub:4444"), new ChromeOptions());
            default:
                throw new IllegalArgumentException("Unsupported browser: " + browserName);
        }
    }
}
// Использование в тесте
WebDriver driver = DriverFactory.createDriver(System.getProperty("browser", "chrome"));

2. Singleton (с осторожностью): Применяю для менеджеров, которые должны быть в единственном экземпляре, например, для управления драйвером в многопоточном окружении через ThreadLocal.

3. Builder: Идеален для создания сложных тестовых данных (пользователей, заказов) с множеством необязательных полей.

User testUser = new User.Builder()
    .withUsername("test_user")
    .withEmail("user@test.com")
    .withActiveStatus(true)
    .build();
// В тесте использую только нужные поля
loginPage.loginWithUser(testUser);

4. Strategy: Позволяет инкапсулировать алгоритмы проверок (стратегии валидации) и выбирать их во время выполнения. Например, разные стратегии проверки результатов поиска: по точному совпадению, по наличию ключевых слов, по фильтрации.

5. Facade: Создаю упрощенный интерфейс для работы со сложными подсистемами. Например, ApiClientFacade скрывает детали настройки HTTP-клиента, аутентификации и парсинга ответов, предоставляя тесту простые методы getUser(), createOrder().

6. Data-Driven Testing (не строго GoF, но критически важный): Отделяю тестовые данные от логики теста. Использую внешние источники (JSON, XML, Excel, БД) для параметризации тестов. В JUnit это @ParameterizedTest, в TestNG — @DataProvider.

7. Fluent Interface / Chain of Invocations: Делаю API page-объектов более читаемым.

// Вместо:
loginPage.enterUsername("user");
loginPage.enterPassword("pass");
loginPage.clickLogin();
// Использую:
loginPage
    .enterUsername("user")
    .enterPassword("pass")
    .clickLogin();

Комбинация паттернов — ключ к успеху. Например, Page Object часто содержит элементы, инициализированные через @FindBy (шаблон Page Factory), а тестовые данные подаются в него через Builder, а сам тест является Data-Driven.