Page Object Model (POM)

Проблема

При написании UI-тестов без структуры весь код взаимодействия со страницей — локаторы, клики, ввод текста — рассеивается прямо по телу тестовых методов. Когда верстальщик переименовывает кнопку или меняет атрибут элемента, приходится вручную искать все места в тестах, где этот элемент упоминается. Дублирование кода нарастает: один и тот же driver.findElement(By.id("search-input")) встречается в десятках тестов. Любое изменение UI превращается в болезненный рефакторинг.

Page Object Model решает эту проблему, инкапсулируя всё взаимодействие со страницей в отдельный класс. Тест описывает что нужно сделать (ввести запрос, нажать кнопку), а Page Object скрывает как это делается (какой локатор, какой тип взаимодействия). Изменение локатора требует правки только в одном месте.

Структура модуля

page-object-model/
├── build.gradle
└── src/
    └── test/
        └── java/
            └── dev/shipovalov/pom/
                ├── GoogleSearchPage.java      # POM главной страницы Google
                ├── GoogleResultsPage.java     # POM страницы результатов поиска
                └── PageObjectModelTest.java   # Тест, использующий Page Objects

Классы страниц расположены в src/test, так как в данном модуле они используются исключительно в тестовом контексте. В реальных проектах Page Objects чаще выносят в src/main для переиспользования между несколькими тестовыми модулями.

Ключевые классы

Класс Назначение
GoogleSearchPage Инкапсулирует поисковую форму: локатор поля ввода, метод search(String query)
GoogleResultsPage Инкапсулирует страницу результатов: получение заголовка, списка результатов
PageObjectModelTest Тест, работающий только через методы Page Objects, без прямых вызовов WebDriver

Пример использования

// Без POM — хрупкий код, локаторы разбросаны по тесту
driver.findElement(By.name("q")).sendKeys("Selenium");
driver.findElement(By.name("btnK")).click();
String title = driver.getTitle();

// С POM — читаемый тест, детали скрыты в Page Object
GoogleSearchPage searchPage = new GoogleSearchPage(driver);
GoogleResultsPage resultsPage = searchPage.search("Selenium");
assertThat(resultsPage.getTitle()).contains("Selenium");

Запуск тестов

./gradlew :page-object-model:test

Отчёт о результатах: page-object-model/build/reports/tests/test/index.html