Какие паттерны проектирования применяются в автотестах?

«Какие паттерны проектирования применяются в автотестах?» — вопрос из категории Паттерны, который задают на 28% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

1. Page Object Model (POM) — фундаментальный паттерн Каждая страница/компонент UI представляется классом, который инкапсулирует:

  • Локаторы элементов
  • Методы взаимодействия
  • Проверки состояния
public class LoginPage
{
    private readonly IWebDriver _driver;
    private readonly By _usernameField = By.Id("username");
    private readonly By _passwordField = By.Id("password");
    private readonly By _submitButton = By.CssSelector("button[type='submit']");

    public LoginPage(IWebDriver driver) => _driver = driver;

    public void EnterCredentials(string username, string password)
    {
        _driver.FindElement(_usernameField).SendKeys(username);
        _driver.FindElement(_passwordField).SendKeys(password);
    }

    public DashboardPage Submit()
    {
        _driver.FindElement(_submitButton).Click();
        return new DashboardPage(_driver); // Возвращает следующую страницу
    }
}

2. Page Factory (упрощённая реализация POM) Использование атрибутов [FindsBy] для автоматической инициализации элементов (хотя в Selenium 4 рекомендуется прямой подход).

3. Loadable Component Pattern Добавление явных ожиданий загрузки страницы/компонента.

public class DashboardPage : LoadableComponent<DashboardPage>
{
    protected override void ExecuteLoad() => Driver.Navigate().GoToUrl("/dashboard");
    protected override bool EvaluateLoadedStatus() => Driver.Title.Contains("Dashboard");
}

4. Singleton для WebDriver Гарантирует единственный экземпляр драйвера на весь тестовый прогон.

public sealed class WebDriverManager
{
    private static IWebDriver _instance;
    private static readonly object _lock = new object();

    public static IWebDriver Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    _instance ??= new ChromeDriver();
                }
            }
            return _instance;
        }
    }
}

5. Factory Method для создания драйверов

public interface IWebDriverFactory
{
    IWebDriver CreateDriver();
}

public class ChromeDriverFactory : IWebDriverFactory
{
    public IWebDriver CreateDriver() => new ChromeDriver();
}

6. Builder для тестовых данных

public class UserBuilder
{
    private string _name = "Default";
    private string _email = "default@test.com";

    public UserBuilder WithName(string name) { _name = name; return this; }
    public UserBuilder WithEmail(string email) { _email = email; return this; }
    public User Build() => new User(_name, _email);
}

// Использование
var user = new UserBuilder().WithName("John").WithEmail("john@example.com").Build();

7. Strategy для выбора стратегии тестирования Например, разные стратегии аутентификации (OAuth, JWT, Basic Auth).

8. Decorator для добавления логирования/ретров

public class LoggingWebDriverDecorator : IWebDriver
{
    private readonly IWebDriver _decoratedDriver;
    public LoggingWebDriverDecorator(IWebDriver driver) => _decoratedDriver = driver;

    public void FindElement(By by)
    {
        Console.WriteLine($"Finding element: {by}");
        return _decoratedDriver.FindElement(by);
    }
}

9. Composite для группировки тестовых шагов

10. Data-Driven Testing через Provider Pattern Отделение тестовых данных от тестовой логики.

Ключевой принцип: Паттерны должны упрощать код, а не усложнять его. Начинайте с POM и добавляйте другие паттерны только при реальной необходимости.