Что такое паттерн Page Object?

Ответ

Page Object (PO) — это ключевой паттерн проектирования в автоматизации UI-тестирования, который инкапсулирует структуру и поведение веб-страницы (или её компонента) в отдельный класс. Каждый такой класс содержит локаторы элементов и методы для взаимодействия с ними, отделяя тестовую логику от деталей реализации страницы.

Основные преимущества с точки зрения QA:

  • Повышение сопровождаемости: При изменении верстки (например, ID элемента) правки вносятся только в один класс Page Object, а не во все тесты.
  • Улучшение читаемости: Тестовые сценарии становятся лаконичными и понятными, так как используют высокоуровневые методы вроде loginPage.login("user", "pass").
  • Устранение дублирования кода: Логика работы со страницей выносится в одно место.
  • Упрощение повторного использования: Компоненты (например, хедер или футер) можно вынести в отдельные Page Object и использовать на разных страницах.

Пример реализации на Java с Selenium WebDriver:

public class LoginPage {
    private WebDriver driver;

    // Локаторы элементов страницы
    private By usernameField = By.id("username");
    private By passwordField = By.id("password");
    private By loginButton = By.id("loginBtn");
    private By errorMessage = By.cssSelector(".alert.error");

    public LoginPage(WebDriver driver) {
        this.driver = driver;
    }

    // Метод для выполнения входа
    public HomePage loginWithValidCredentials(String username, String password) {
        driver.findElement(usernameField).sendKeys(username);
        driver.findElement(passwordField).sendKeys(password);
        driver.findElement(loginButton).click();
        return new HomePage(driver); // Возвращаем Page Object следующей страницы
    }

    // Метод для негативного теста
    public String loginWithInvalidCredentials(String username, String password) {
        driver.findElement(usernameField).sendKeys(username);
        driver.findElement(passwordField).sendKeys(password);
        driver.findElement(loginButton).click();
        return driver.findElement(errorMessage).getText(); // Возвращаем текст ошибки
    }
}

Использование в тесте (JUnit):

@Test
public void successfulLoginTest() {
    LoginPage loginPage = new LoginPage(driver);
    HomePage homePage = loginPage.loginWithValidCredentials("testUser", "testPass");
    assertTrue(homePage.isUserMenuDisplayed());
}

Ответ 18+ 🔞

А, ну вот, смотри, объясняю на пальцах, что за зверь такой — Page Object. Это, блядь, как если бы ты пришёл в бар, а там вместо того чтобы каждый раз бармену объяснять: «Дай мне стакан, налей туда водки, кинь лёд, дольку лайма» — у тебя просто есть кнопка «Мохито». Нажал — и всё, готово. Вот Page Object — это и есть такая кнопка, только для веб-страницы.

Если по-умному, то это паттерн, который всю эту хуйню — поля ввода, кнопки, таблицы — засовывает в отдельный класс. Чтобы твои тесты не превращались в адский спагетти-код, где перемешаны «найти элемент по ID» и «проверить, что заказ создался». Теперь это два разных мира.

Ну и нахуя это надо, спросишь ты? А вот нахуя:

  • Чинить в одном месте. Представь, фронтендеры взяли и поменяли id="loginBtn" на data-qa="submit". Без Page Object тебе пришлось бы, ёпта, бегать по всем сотням тестов и менять этот локатор. Это пиздец. А с Page Object — ты зашёл в один класс LoginPage, поправил одну строчку, и всё, ты красавчик. Сопровождаемость — овердохуища.
  • Читать как книжку. Тест теперь выглядит не как шифровка для посвящённых, а как нормальная инструкция: loginPage.enterCredentials(...); homePage.checkOrder();. Даже менеджер, если заглянет, может примерно понять, что происходит. Удивление пиздец, правда?
  • Не повторяться. Логику «как залогиниться» ты пишешь ОДИН РАЗ в методе login. И потом просто вызываешь её из двадцати разных тестов. Никакого копипаста, который потом, когда надо что-то поменять, выстрелит тебе в жопу.
  • Собирать из кубиков. Сделал класс для шапки сайта (HeaderPage) — и таскай его на все страницы, где эта шапка есть. Удобно, чё.

Смотри, как это выглядит в коде (Java + Selenium):

public class LoginPage {
    private WebDriver driver;

    // Вот тут мы храним все эти ебучки-локаторы, чтоб они были в одном месте
    private By usernameField = By.id("username");
    private By passwordField = By.id("password");
    private By loginButton = By.id("loginBtn");
    private By errorMessage = By.cssSelector(".alert.error");

    public LoginPage(WebDriver driver) {
        this.driver = driver;
    }

    // Метод для нормального входа. Залогинился — и тебя перекинуло на домашнюю страницу
    public HomePage loginWithValidCredentials(String username, String password) {
        driver.findElement(usernameField).sendKeys(username);
        driver.findElement(passwordField).sendKeys(password);
        driver.findElement(loginButton).click();
        return new HomePage(driver); // Возвращаем уже следующий Page Object
    }

    // А это для негативщины. Ввёл хуйню — получи сообщение об ошибке
    public String loginWithInvalidCredentials(String username, String password) {
        driver.findElement(usernameField).sendKeys(username);
        driver.findElement(passwordField).sendKeys(password);
        driver.findElement(loginButton).click();
        return driver.findElement(errorMessage).getText();
    }
}

А вот как этим потом в тесте пользуются:

@Test
public void successfulLoginTest() {
    // Создаём объект страницы логина
    LoginPage loginPage = new LoginPage(driver);
    // Вызываем метод — и нас сразу кидает на HomePage
    HomePage homePage = loginPage.loginWithValidCredentials("testUser", "testPass");
    // И проверяем, что зашли успешно
    assertTrue(homePage.isUserMenuDisplayed());
}

Короче, чувак, если не хочешь, чтобы твоя автотестовая фантастика превратилась в хоррор с тоннами одинакового кода и вечными правками — бери Page Object на вооружение. Изначально, конечно, придётся немного подумать, как структурировать, но потом ты сам себе спасибо скажешь. Терпения, блядь, ноль — поддерживать кучу размазанных по тестам локаторов. А так — красота.