Ответ
В автоматизации тестирования паттерны проектирования решают проблемы поддержки, читаемости и масштабируемости тестового кода.
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 и добавляйте другие паттерны только при реальной необходимости.
Ответ 18+ 🔞
А, слушай, вот эта вся хуйня про паттерны в автотестах — это ж на самом деле не просто умные слова, чтобы на собеседовании понтоваться. Это реально чтобы твой код не превратился в такую свалку, что потом сам через месяц разбираться будешь, как в тёмном лесу, и желания жить не останется. Ну, типа, чтобы поддерживать, читать и масштабировать это всё было не пиздец как больно.
1. Page Object Model (POM) — это типа священный грааль, основа основ Вместо того чтобы раскидывать локаторы по всем тестам, как говно по вентилятору, ты каждую страницу или компонент засовываешь в отдельный класс. Там у тебя и локаторы, и методы что-то сделать, и проверки. Красота!
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, то просто логин-пароль. Выбирай стратегию — и вперёд.
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 — святое дело! Отдели данные от логики, блядь! Не надо хардкодить сто одно значение прямо в тесте. Вынеси в провайдер, в файл, в базу — куда угодно. Тест должен быть один, а данных — овердохуища.
И главное, запомни, чувак: все эти паттерны — они как инструменты. Не надо брать кувалду, чтобы забить гвоздь в стену из гипсокартона. Начни с Page Object Model, а остальное подтягивай только тогда, когда реально почувствуешь, что без этого уже пиздец и больно. А то можно так наархитектурить, что сам потом плакать будешь.