Объектная модель страницы (Page Object Model — POM) — это шаблон проектирования, широко используемый в автоматизации тестирования. В этой статье мы рассмотрим использование POM в Selenium.
Содержание
- В чем суть применения POM в Selenium?
- Преимущества POM
- Как реализовать POM?
- Что такое Page Factory в Selenium?
- Тест-кейс Guru99 с использованием Page Factory
- AjaxElementLocatorFactory
Подпишитесь на наш ТЕЛЕГРАМ КАНАЛ ПО АВТОМАТИЗАЦИИ ТЕСТИРОВАНИЯ
В чем суть применения POM в Selenium?
Паттерн POM предполагает создание репозитория объектов для элементов веб-интерфейса. Преимуществом здесь является уменьшение дублирования кода и улучшение сопровождения тестов.
Согласно этой модели, для каждой веб-страницы в приложении должен существовать соответствующий класс Page. Он будет идентифицировать элементы данной веб-страницы, а также содержать методы Page, выполняющие операции с этими элементами. Имя этих методов должно соответствовать выполняемой ими задаче. Т.е., если загрузчик ожидает появления платежного шлюза, то имя метода POM может быть waitForPaymentScreenDisplay().

Переходим к использованию паттерна POM в Selenium.
Запуск автоматизации пользовательского интерфейса в Selenium WebDriver — не самая сложная задача. Нужно просто найти элементы и выполнить над ними операции.
Рассмотрим этот простой сценарий для входа на сайт:

Как можно заметить, все, что мы делаем, — это поиск элементов и заполнение их значениями.
Это небольшой скрипт. Его сопровождение выглядит достаточно просто. Но со временем набор тестов будет расти. По мере того, как вы добавляете в код все больше и больше строк, он становится сложнее.
Основная проблема при обслуживании скриптов заключается в том, что если 10 различных скриптов используют один и тот же элемент страницы, то при любом изменении этого элемента необходимо изменить все 10 скриптов. Это отнимает много времени и чревато ошибками.
Более эффективным подходом к обслуживанию скриптов является создание отдельного файла класса, который будет находить веб-элементы, заполнять их или проверять. Этот класс может быть повторно использован во всех скриптах, использующих данный элемент. В будущем, если в веб-элементе произойдет изменение, нам нужно будет исправить всего в один файл класса, а не 10 различных скриптов.
Такой подход в Selenium называется объектной моделью страницы (POM). Он позволяет сделать код более читаемым, сопровождаемым и многократно используемым.

Преимущества POM
- Паттерн POM предполагает, что операции и потоки в пользовательском интерфейсе должны быть отделены от верификации. Эта концепция делает код чище и проще для понимания.
- Второе преимущество заключается в том, что репозиторий объектов не зависит от тестовых случаев, поэтому мы можем использовать один и тот же репозиторий объектов для разных целей с разными инструментами. Например, мы можем интегрировать объектную модель страницы в Selenium с TestNG/JUnit для функционального тестирования и в то же время с JBehave/Cucumber для приемочного тестирования.
- Благодаря многоразовым методам страниц в классах POM код становится более оптимизированым, а его размер уменьшается.
- Методы получают более реалистичные имена, которые можно легко сопоставить с операцией, происходящей в пользовательском интерфейсе. Например, если после нажатия на кнопку мы попадаем на главную страницу, то имя метода будет выглядеть как
gotoHomePage().
Как реализовать POM?
Это базовая структура POM, в которой все веб-элементы AUT (тестируемое приложение — Application Under Testing) и метод, работающий с этими веб-элементами, хранятся внутри файла класса. Такая задача, как проверка, должна быть выделена в отдельную часть методов Test.

Пример реализации POM
Шаг 1. Перейдите на демонстрационный сайт Guru99.

Шаг 2. На главной странице проверьте наличие текста «Guru99 Bank».

Шаг 3. Войдите в приложение.

Шаг 4. Убедитесь, что на главной странице присутствует текст «Manger Id: demo».

Здесь мы имеем дело с 2 страницами:
- Страница входа в систему.
- Главная страница (отображается после входа в систему).
Соответственно, мы создаем 2 POM в классах Selenium.
POM страницы входа на демо-сайт Guru99:
package pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class Guru99Login {
WebDriver driver;
By user99GuruName = By.name("uid");
By password99Guru = By.name("password");
By titleText =By.className("barone");
By login = By.name("btnLogin");
public Guru99Login(WebDriver driver){
this.driver = driver;
}
//Set user name in textbox
public void setUserName(String strUserName){
driver.findElement(user99GuruName).sendKeys(strUserName);
}
//Set password in password textbox
public void setPassword(String strPassword){
driver.findElement(password99Guru).sendKeys(strPassword);
}
//Click on login button
public void clickLogin(){
driver.findElement(login).click();
}
//Get the title of Login Page
public String getLoginTitle(){
return driver.findElement(titleText).getText();
}
/**
* This POM method will be exposed in test case to login in the application
* @param strUserName
* @param strPasword
* @return
*/
public void loginToGuru99(String strUserName,String strPasword){
//Fill user name
this.setUserName(strUserName);
//Fill password
this.setPassword(strPasword);
//Click Login button
this.clickLogin();
}
}
POM главной страницы демо-сайта Guru99:
package pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class Guru99HomePage {
WebDriver driver;
By homePageUserName = By.xpath("//table//tr[@class='heading3']");
public Guru99HomePage(WebDriver driver){
this.driver = driver;
}
//Get the User name from Home Page
public String getHomePageDashboardUserName(){
return driver.findElement(homePageUserName).getText();
}
}
Guru99 Simple POM in Selenium Test case
package test;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import pages.Guru99HomePage;
import pages.Guru99Login;
public class Test99GuruLogin {
String driverPath = "C:\\geckodriver.exe";
WebDriver driver;
Guru99Login objLogin;
Guru99HomePage objHomePage;
@BeforeTest
public void setup(){
System.setProperty("webdriver.gecko.driver", driverPath);
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://demo.guru99.com/V4/");
}
/**
* This test case will login in http://demo.guru99.com/V4/
* Verify login page title as guru99 bank
* Login to application
* Verify the home page using Dashboard message
*/
@Test(priority=0)
public void test_Home_Page_Appear_Correct(){
//Create Login Page object
objLogin = new Guru99Login(driver);
//Verify login page title
String loginPageTitle = objLogin.getLoginTitle();
Assert.assertTrue(loginPageTitle.toLowerCase().contains("guru99 bank"));
//login to application
objLogin.loginToGuru99("mgr123", "mgr!23");
// go the next page
objHomePage = new Guru99HomePage(driver);
//Verify home page
Assert.assertTrue(objHomePage.getHomePageDashboardUserName().toLowerCase().contains("manger id : mgr123"));
}
Что такое фабрика страниц в Selenium?
Фабрика страниц (Page Factory) в Selenium — это встроенная и очень оптимизированния концепция POM для Selenium WebDriver. Ее используют для инициализации объектов Page или для создания экземпляра самого объекта Page. Она также применяется для инициализации элементов класса Page без использования "FindElement/s".
Здесь мы также следуем концепции разделения хранилища объектов страницы и тестовых методов. Кроме того, с помощью класса PageFactory в Selenium мы используем аннотации @FindBy для поиска веб-элементов. Для инициализации веб-элементов мы используем метод initElements.

@FindBy может принимать в качестве атрибутов tagName, partialLinkText, name, linkText, id, css, className, xpath.
Рассмотрим тот же пример, что и выше, с использованием Page Factory.
Страница входа на сайт Guru99 с использованием Page Factory:
package PageFactory;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class Guru99Login {
/**
* All WebElements are identified by @FindBy annotation
*/
WebDriver driver;
@FindBy(name="uid")
WebElement user99GuruName;
@FindBy(name="password")
WebElement password99Guru;
@FindBy(className="barone")
WebElement titleText;
@FindBy(name="btnLogin")
WebElement login;
public Guru99Login(WebDriver driver){
this.driver = driver;
//This initElements method will create all WebElements
PageFactory.initElements(driver, this);
}
//Set user name in textbox
public void setUserName(String strUserName){
user99GuruName.sendKeys(strUserName);
}
//Set password in password textbox
public void setPassword(String strPassword){
password99Guru.sendKeys(strPassword);
}
//Click on login button
public void clickLogin(){
login.click();
}
//Get the title of Login Page
public String getLoginTitle(){
return titleText.getText();
}
/**
* This POM method will be exposed in test case to login in the application
* @param strUserName
* @param strPasword
* @return
*/
public void loginToGuru99(String strUserName,String strPasword){
//Fill user name
this.setUserName(strUserName);
//Fill password
this.setPassword(strPasword);
//Click Login button
this.clickLogin();
}
}
Главная страница Guru99 с использованием Page Factory:
package PageFactory;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class Guru99HomePage {
WebDriver driver;
@FindBy(xpath="//table//tr[@class='heading3']")
WebElement homePageUserName;
public Guru99HomePage(WebDriver driver){
this.driver = driver;
//This initElements method will create all WebElements
PageFactory.initElements(driver, this);
}
//Get the User name from Home Page
public String getHomePageDashboardUserName(){
return homePageUserName.getText();
}
}
Тест-кейс Guru99 с использованием Page Factory
package test;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import PageFactory.Guru99HomePage;
import PageFactory.Guru99Login;
public class Test99GuruLoginWithPageFactory {
String driverPath = "C:\\geckodriver.exe";
WebDriver driver;
Guru99Login objLogin;
Guru99HomePage objHomePage;
@BeforeTest
public void setup(){
System.setProperty("webdriver.gecko.driver", driverPath);
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://demo.guru99.com/V4/");
}
/**
* This test go to http://demo.guru99.com/V4/
* Verify login page title as guru99 bank
* Login to application
* Verify the home page using Dashboard message
*/
@Test(priority=0)
public void test_Home_Page_Appear_Correct(){
//Create Login Page object
objLogin = new Guru99Login(driver);
//Verify login page title
String loginPageTitle = objLogin.getLoginTitle();
Assert.assertTrue(loginPageTitle.toLowerCase().contains("guru99 bank"));
//login to application
objLogin.loginToGuru99("mgr123", "mgr!23");
// go the next page
objHomePage = new Guru99HomePage(driver);
//Verify home page
Assert.assertTrue(objHomePage.getHomePageDashboardUserName().toLowerCase().contains("manger id : mgr123"));
}
}
Полная структура проекта будет выглядеть так, как показано на схеме:

AjaxElementLocatorFactory
AjaxElementLocatorFactory — это концепция отложенной загрузки PageFactory в Selenium. Ее применяют для поиска веб-элементов только тогда, когда эти элементы используются в какой-либо операции. Она назначает таймаут для веб-элементов объектному классу страницы. Класс AjaxElementLocatorFactory является одним из ключевых преимуществ использования паттерна Page Factory в Selenium.
Здесь при выполнении операции над элементом ожидание его видимости начинается только с момента поиска. Если элемент не будет найден в течение заданного интервала времени, выполнение тестового примера выдаст исключение NoSuchElementException.

Выводы
- Объектная модель страницы в Selenium WebDriver представляет собой паттерн проектирования Object Repository.
- Объектная модель страниц Selenium позволяет сделать наш код тестирования сопровождаемым и многократно используемым.
- Page Factory — это оптимизированный способ создания хранилища объектов в концепции Page Object Model.
- AjaxElementLocatorFactory — это концепция отложенной загрузки в Page Factory, позволяющая идентифицировать веб-элементы только тогда, когда они используются в какой-либо операции.
Перевод статьи «Page Object Model (POM) & Page Factory in Selenium».

Пингбэк: 25 вопросов на собеседовании по Playwright
Пингбэк: Большой учебник по Selenium
Пингбэк: Вопросы по Appium на собеседовании
Пингбэк: Playwright vs Selenium: гайд по современной автоматизации тестирования