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

Какие знаешь паттерны проектирования автотестов?

2.2 Middle🔥 171 комментариев
#Архитектура приложений#Фреймворки тестирования

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

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

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

Паттерны проектирования в автоматизации тестирования

В автоматизации тестирования, особенно в UI и API тестировании, активно применяются паттерны проектирования для создания поддерживаемого, масштабируемого и переиспользуемого кода. Вот ключевые паттерны, которые я использую в своей практике.

1. Page Object Model (POM) и его вариации

POM — фундаментальный паттерн для UI-автотестов. Каждая страница приложения инкапсулируется в отдельный класс, содержащий локаторы элементов и методы для взаимодействия с ними.

# Пример Page Object в Python + Selenium
class LoginPage:
    def __init__(self, driver):
        self.driver = driver
        self.username_field = (By.ID, "username")
        self.password_field = (By.ID, "password")
        self.submit_button = (By.CSS_SELECTOR, "button[type='submit']")

    def login(self, username, password):
        self.driver.find_element(*self.username_field).send_keys(username)
        self.driver.find_element(*self.password_field).send_keys(password)
        self.driver.find_element(*self.submit_button).click()
        return HomePage(self.driver)  # Возвращаем объект следующей страницы

Эволюцией POM стали:

  • Page Factory (упрощает инициализацию элементов в Selenium, хотя в современных версиях используется реже).
  • Page Element или Loadable Component (добавляет явные ожидания загрузки страницы).
  • Page Object + Component Object — выделение переиспользуемых компонентов (например, хедера, модальных окон) в отдельные классы.

2. Screenplay Pattern (или Actor Pattern)

Более современная и гибкая альтернатива POM, основанная на принципах поведенчески-ориентированного проектирования. Акцент смещается с "страниц" на "действия" и "способности" актера (пользователя).

// Пример на Java с Serenity BDD
Actor user = Actor.named("Петр");
user.can(BrowseTheWeb.with(webDriver));
user.attemptsTo(
    Open.browserOn().the(LoginPage.class),
    Enter.theValue("standard_user").into(LoginPage.USERNAME_FIELD),
    Enter.theValue("secret_sauce").into(LoginPage.PASSWORD_FIELD),
    Click.on(LoginPage.LOGIN_BUTTON)
);

Преимущества: лучшее разделение ответственности, высокая переиспользуемость шагов, тесты читаются как пользовательские сценарии.

3. Data-Driven Testing (DDT)

Паттерн, при котором тестовые данные отделены от тестовой логики. Это позволяет запускать один и тот же тест с множеством наборов данных.

import pytest
import pandas as pd

# Тест параметризуется данными из CSV
@pytest.mark.parametrize("username, password, expected", [
    ("user1", "pass1", True),
    ("locked_user", "pass", False),
])
def test_login(username, password, expected):
    # ... логика теста
    assert login_result == expected

Источники данных: CSV, JSON, Excel, БД. Часто используется в связке с Parameterized Tests в фреймворках (JUnit, TestNG, Pytest).

4. Fluent Interface / Chain of Invocations

Позволяет строить читаемые "цепочки вызовов", делая код тестов похожим на естественный язык.

// Пример с WebdriverIO
browser
    .url('/login')
    .$('#username').setValue('test')
    .$('#password').setValue('pass123')
    .$('button').click()
    .expect($('.welcome-message')).toBeDisplayed();

5. Singleton

Часто применяется для управления драйвером браузера (Driver Manager) или клиентом API, чтобы гарантировать существование только одного экземпляра в рамках тестового запуска (или потока).

public class WebDriverManager {
    private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();

    private WebDriverManager() {} // Приватный конструктор

    public static WebDriver getDriver() {
        if (driver.get() == null) {
            driver.set(new ChromeDriver());
        }
        return driver.get();
    }
}

6. Factory Method

Используется для создания объектов со сложной логикой инициализации. Классический пример — фабрика драйверов (для Chrome, Firefox, Safari) или фабрика страниц.

class WebDriverFactory:
    @staticmethod
    def get_driver(browser_name: str):
        if browser_name == "chrome":
            return ChromeDriver()
        elif browser_name == "firefox":
            return FirefoxDriver()
        else:
            raise ValueError(f"Unsupported browser: {browser_name}")

7. Strategy Pattern

Полезен, когда необходимо менять алгоритм или поведение в рантайме. Например, разные стратегии аутентификации в API-тестах (OAuth, Basic Auth, API Key) или разные стратегии генерации тестовых данных.

interface AuthStrategy {
    authenticate(request: Request): Request;
}

class ApiKeyStrategy implements AuthStrategy {
    authenticate(request: Request): Request {
        request.headers.set('X-API-Key', process.env.API_KEY);
        return request;
    }
}

8. Decorator Pattern

Часто используется для добавления кросс-функционального поведения к тестам или шагам: логирование, тайминг, повторные попытки (retry), скриншоты при падении.

# Pytest fixture как декоратор для логирования
@pytest.fixture
def logged_test(request):
    print(f"\nStarting test: {request.node.name}")
    yield
    print(f"\nFinished test: {request.node.name}")

@logged_test
def test_something():
    assert True

9. Facade Pattern

Предоставляет упрощенный интерфейс к сложной подсистеме. В автотестах это может быть "Test Facade" или "API Client", который скрывает сложность низкоуровневых HTTP-запросов за простыми методами createUser(), getOrder().

Выбор паттерна зависит от контекста:

  • POM/Screenplay — для сложных UI-проектов.
  • DDT и Strategy — для тестов, чувствительных к данным.
  • Singleton/Factory — для управления ресурсами.
  • Decorator/Facade — для улучшения инфраструктуры тестов.

Главное — не стремиться применить все сразу, а использовать комбинацию паттернов, которая решает конкретные проблемы поддержки, читаемости и стабильности вашего тестового фреймворка. Правильно выбранные паттерны снижают стоимость поддержки тестов и ускоряют разработку новых сценариев.