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

Ответ

Основное преимущество 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, а не в сотнях тестовых методов.

Ответ 18+ 🔞

Слушай, а вот объясни мне, как человеку, который уже десять раз переписывал тесты из-за того, что фронтендеры кнопку переименовали. В чём, блядь, соль этого вашего Page Object Model? Ну кроме того, что это модно и все так делают?

А соль, оказывается, проще пареной репы. Всё дело в стоимости поддержки, ёпта. Представь: у тебя сотня тестов, и в каждом ты ищешь кнопку логина по id="login-btn". И тут приходит дизайнер и говорит: "Ребят, мы её переименовали в data-qa="sign-in"". Без POM тебе придётся, блядь, проходить по всем этим сотням файлов и менять локатор. Это пиздец, это ад, это терпения ноль ебать. А с POM ты идёшь в один-единственный класс LoginPage, правишь одно поле — и всё, ты красавчик. В рот мне чих-пых, вот она, магия!

И это не всё. Читаемость, сука, вырастает в овердохуища раз. Твой тест перестаёт быть инструкцией для робота: "возьми это, кликни то". Он начинает говорить на человеческом языке.

Смотри, как было раньше, пиздопроебибна история:

@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"));
}

Что тут происходит? Хуй с горы поймёт. Какие-то поля, какие-то клики. А теперь гляди, как должно быть:

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();
}

Видишь разницу? Тест теперь не про "как", а про "что". Открыл страницу логина, залогинился, проверил, что вошёл. Ядрёна вошь, да это же почти как требования читать! Любой менеджер, даже тот, который в коде ни хуя не шарит, посмотрит и скажет: "Ага, логин тестируем".

И третий козырь — сложная логика. Вот, например, если на той же странице логина нужно ещё и капчу ввести, или чекбокс "запомнить меня" нажать. Без POM ты эту поебень будешь копипастить в каждом втором тесте. А с POM ты просто добавляешь пару строк в метод login() внутри класса страницы — и все тесты автоматически начинают использовать новую, улучшенную логику. Ебать мои старые костыли, вот это эффективность!

Короче, POM — это не просто паттерн, это, блядь, способ сохранить рассудок, когда проект растёт, а фронт меняется каждую неделю. Доверия ебать ноль к их стабильности, зато с POM хоть какая-то защита есть.