В чем преимущество паттерна Page Object Model (POM) перед прямым использованием локаторов в тесте?

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

Ответ

Основное преимущество POM — это снижение стоимости поддержки и повышение читаемости автотестов за счет инкапсуляции логики взаимодействия с элементами страницы в отдельные классы.

Конкретные выгоды для проектов на Selenium/Selenide:

  1. Устойчивость к изменениям в верстке: Если изменился локатор кнопки Login, его нужно поправить только в одном месте — в классе LoginPage. Без POM пришлось бы искать и править этот локатор во всех десятках тестов, где он используется.
  2. Улучшенная читаемость и реюзабилити: Тест-код описывает что мы делаем (логинимся, добавляем товар в корзину), а не как (ищем поле, вводим текст, кликаем). Это делает тесты короче и понятнее бизнес-аналитикам.
  3. Единая точка для сложных взаимодействий: Если для входа нужно выполнить несколько шагов (ввести логин, пароль, решить капчу), эта логика инкапсулирована в метод login() объекта страницы. Тесты используют этот высокоуровневый метод.

Сравнение на примере Selenide (Java):

// ПЛОХО: Локаторы и логика размазаны по тесту
@Test
public void testLoginWithoutPOM() {
    open("/login");
    $(By.id("username")).setValue("user");
    $(By.id("password")).setValue("pass");
    $(By.id("login-button")).click();
    $(By.className("welcome-msg")).shouldHave(text("Welcome"));
}

// ХОРОШО: Использование POM
public class LoginPage {
    private SelenideElement usernameField = $(By.id("username"));
    private SelenideElement passwordField = $(By.id("password"));
    private SelenideElement loginButton = $(By.id("login-button"));
    private SelenideElement welcomeMessage = $(By.className("welcome-msg"));

    public HomePage login(String user, String pass) {
        usernameField.setValue(user);
        passwordField.setValue(pass);
        loginButton.click();
        return new HomePage(); // Возвращаем объект следующей страницы
    }

    public void assertWelcomeMessage() {
        welcomeMessage.shouldHave(text("Welcome"));
    }
}

// Тест становится чистым и выразительным
@Test
public void testLoginWithPOM() {
    LoginPage loginPage = open("/login", LoginPage.class);
    HomePage homePage = loginPage.login("user", "pass");
    homePage.assertUserIsLoggedIn();
}

При рефакторинге верстки изменения локаторов будут сосредоточены в классах Page Object, а не в сотнях тестовых методов.