← Назад к вопросам

В чем разница между Page Factory и Page Object Model?

1.8 Middle🔥 171 комментариев
#Selenium и UI автоматизация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между Page Factory и Page Object Model

Начнем с ключевого определения: Page Object Model (POM) — это широко распространенный паттерн (шаблон проектирования) в автоматизации тестирования веб-приложений, целью которого является повышение читаемости, поддерживаемости и уменьшения дублирования кода. Основная идея POM заключается в том, что каждый веб-страница или ее значимый компонент представляется в виде отдельного класса. Этот класс содержит:

  • Локаторы элементов (например, XPath, CSS Selectors).
  • Методы, которые моделируют пользовательские действия на этой странице (например, login(username, password), searchProduct(name)).

Таким образом, тестовые сценарии используют эти объекты страниц, взаимодействуя с ними через их методы, и не работают напрямую с локаторами или низкоуровневыми командами драйвера (Selenium). Это абстрагирует тесты от изменений в структуре HTML.

Page Factory как реализация POM

Page Factory — это не альтернатива POM, а конкретный механизм его реализации, предоставляемый библиотекой Selenium для упрощения инициализации элементов страницы (Page Objects) в этом паттерне. Он был особенно популярен в Selenium 2 (WebDriver). Основная его функция — автоматическое проявление (проинициализация) полей класса, объявленных с помощью аннотации @FindBy, при создании объекта страницы.

Главное отличие заключается в том, что Page Factory — это инструмент внутри паттерна POM, который решает одну конкретную задачу: удобное инициализация элементов.

Сравнение на практике: Классический POM vs POM с Page Factory

Рассмотрим пример моделирования страницы логина.

1. Page Object Model без использования Page Factory (классический подход):

public class LoginPage {
    // Локаторы хранятся как строковые константы
    private static final String USERNAME_FIELD = "id=username";
    private static final String PASSWORD_FIELD = "css=input[type='password']";
    private static final String LOGIN_BUTTON = "xpath=//button[text()='Войти']";

    private WebDriver driver;

    // Конструктор получает драйвер
    public LoginPage(WebDriver driver) {
        this.driver = driver;
    }

    // Методы страницы сами ищут элементы при каждом вызове
    public void login(String user, String pass) {
        driver.findElement(By.id(USERNAME_FIELD.split("=")[1])).sendKeys(user);
        driver.findElement(By.cssSelector(PASSWORD_FIELD.split("=")[1])).sendKeys(pass);
        driver.findElement(By.xpath(LOGIN_BUTTON.split("=")[1])).click();
    }
}

В этом подходе локаторы объявлены отдельно, и каждый метод действия (login) самостоятельно инициализирует элементы через driver.findElement(...).

2. Page Object Model с использованием Page Factory:

public class LoginPage {
    // Аннотация @FindBy связывает поле (WebElement) с локатором
    @FindBy(id = "username")
    private WebElement usernameField;

    @FindBy(css = "input[type='password']")
    private WebElement passwordField;

    @FindBy(xpath = "//button[text()='Войти']")
    private WebElement loginButton;

    private WebDriver driver;

    public LoginPage(WebDriver driver) {
        this.driver = driver;
        // Ключевая строка: Инициализация элементов через PageFactory
        PageFactory.initElements(driver, this);
    }

    // Методы страницы используют уже проинициализированные WebElement поля
    public void login(String user, String pass) {
        usernameField.sendKeys(user);
        passwordField.sendKeys(pass);
        loginButton.click();
    }
}

Здесь PageFactory.initElements(driver, this) в конструкторе выполняет "магию": она сканирует класс, находит все поля с аннотацией @FindBy, и для каждого создает "proxy" (обертку) WebElement. При первом взаимодействии с этим полем (например, usernameField.sendKeys()) происходит реальный поиск элемента в DOM.

Ключевые различия в таблице

КритерийPage Object Model (Паттерн)Page Factory (Инструмент реализации)
СущностьАрхитектурный паттерн, принцип организации кода.Конкретный класс/механизм в Selenium для поддержки этого паттерна.
Основная задачаАбстрагирование страниц в объекты, разделение тестов и локаторов, повышение поддерживаемости.Автоматическая инициализация полей-элементов (WebElement) в объектах страниц.
Использование локаторовЛокаторы могут храниться в любом виде (строки, By объекты) и использоваться в методах.Локаторы объявляются через аннотации @FindBy прямо над полями WebElement.
Инициализация элементовЭлементы обычно инициализируются "лениво" (при каждом вызове) внутри методов действий.Элементы инициализируются однократно при вызове PageFactory.initElements(), часто в конструкторе.
Современный контекстПаттерн остается крайне актуальным и фундаментальным.В Selenium 4 использование PageFactory стало менее распространенным. Многие фреймворки предпочитают другие подходы (например, явную инициализацию через driver.findElement в методах или использование кастомных findBy методов) из-за некоторых ограничений initElements.

Ограничения и современные альтернативы Page Factory

Несмотря на удобство, у Page Factory есть недостатки, которые снизили его популярность:

  • Ленивая загрузка (Lazy Load): Инициализация WebElement происходит при первом использовании. Это может маскировать проблемы: если локатор неверен, ошибка возникнет не при создании страницы, а только во время теста.
  • Сложность с динамически изменяющимися элементами: Если DOM меняется после инициализации, "proxy" объекты могут не обновиться корректно.
  • Чуть менее явный код: Локаторы "скрыты" в аннотации над полем, что иногда может затруднять чтение.

Современные подходы часто возвращаются к более явному стилю POM без PageFactory, но с улучшениями:

public class ModernLoginPage {
    private WebDriver driver;

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

    // Элементы инициализируются через удобные методы-помощники
    private WebElement usernameField() { return driver.findElement(By.id("username")); }
    private WebElement passwordField() { return driver.findElement(By.cssSelector("input[type='password']")); }
    private WebElement loginButton() { return driver.findElement(By.xpath("//button[text()='Войти']")); }

    public void login(String user, String pass) {
        usernameField().sendKeys(user);
        passwordField().sendKeys(pass);
        loginButton().click();
    }
}

Итог

Page Object Model — это архитектурный принцип, которого ты должен соблюдать для создания устойчивых тестовых фреймворков. Page Factory — это один из инструментов, который Selenium предлагал для удобной реализации этого принципа, преимущественно для автоматического связывания локаторов с полями класса. В сегодняшней практике сам паттерн POM остается обязательным, но выбор конкретного способа инициализации элементов (PageFactory, явные методы, другие библиотеки) зависит от предпочтений команды и особенностей проекта.

В чем разница между Page Factory и Page Object Model? | PrepBro