Page Object Model (POM) и Page Factory в Selenium
Какво е обектен модел на страница?
Page Object Model (POM) е шаблон за проектиране, широко използван в автоматизацията на тестовете, който създава Object Repository за елементи на уеб интерфейса. Предимството на модела е, че намалява дублирането на код и подобрява поддръжката на теста.
При този модел за всяка уеб страница в приложението трябва да има съответен клас страница. Този клас Page ще идентифицира WebElements на тази уеб страница и също така съдържа Page методи, които извършват операции върху тези WebElements. Името на тези методи трябва да бъде дадено според задачата, която изпълняват, т.е. ако товарачът чака да се появи платежният шлюз, името на POM метода може да бъде waitForPaymentScreenDisplay().
Защо Page Object Model?
Стартиране на автоматизация на потребителския интерфейс в Selenium WebDriver НЕ е трудна задача. Просто трябва да намерите елементи, да извършите операции върху него.
Помислете за този прост скрипт, за да влезете в уебсайт
Както можете да видите, всичко, което правим, е да намираме елементи и да попълваме стойности за тези елементи.
Това е малък скрипт. Поддръжката на скрипт изглежда лесна. Но с времето наборът от тестове ще расте. Докато добавяте все повече и повече редове към кода си, нещата стават трудни.
Основният проблем с поддръжката на скриптове е, че ако 10 различни скрипта използват един и същ елемент на страницата, с всяка промяна в този елемент, трябва да промените всичките 10 скрипта. Това отнема време и е податливо на грешки.
По-добър подход към поддръжката на скрипта е да се създаде отделен клас файл, който да намира уеб елементи, да ги попълва или проверява. Този клас може да се използва повторно във всички скриптове, използващи този елемент. В бъдеще, ако има промяна в уеб елемента, трябва да направим промяната само в 1 клас файл, а не в 10 различни скрипта.
Този подход се нарича Page Object Model in Selenium. Това помага да се направи кодът по-четлив, поддържаем и многократно използваем.
Предимства на POM
- Шаблонът за проектиране на обект на страница казва, че операциите и потоците в потребителския интерфейс трябва да бъдат отделени от проверката. Тази концепция прави нашия код по-чист и лесен за разбиране.
- Второто предимство е, че хранилището на обекти е независимо от тестови случаи, така че можем да използваме едно и също хранилище на обекти за различни цели с различни инструменти. Например, можем да интегрираме Page Object Model в Selenium с TestNG/JUnit за функционални Тестване и в същото време с JBehave/Cucumber за тестване за приемане.
- Кодът става по-малко и оптимизиран поради методите за повторно използване на страници в POM класовете.
- Методите получават по-реалистични имена, които могат лесно да бъдат съпоставени с операцията, извършвана в потребителския интерфейс. т.е. ако след щракване върху бутона стигнем до началната страница, името на метода ще бъде като 'gotoHomePage()'.
Как да внедрим POM?
Обикновен POM:
Това е основната структура на рамката на обектния модел на страницата, където всички уеб елементи на AUT и методът, който работи с тези уеб елементи, се поддържа във файл на клас. Задача като проверка трябва да бъде отделна като част от тестовите методи.
Пълен пример
тестов случай: Отидете на демонстрационния сайт на Guru99.
Стъпка 1) Отидете на Guru99 Demo Site
Стъпка 2) В началната страница проверете текста „Guru99 Bank“.
Стъпка 3) Влезте в приложението
Стъпка 4) Проверете дали началната страница съдържа текст като „Идентификационен номер на мениджър: демонстрация“
Тук имаме работа с 2 страници
- Логин страница
- Начална страница (показва се след като влезете)
Съответно създаваме 2 POM в Selenium класове
Guru99 Страница за вход POM
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(); } }
Guru99 Начална страница POM в Selenium
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 Обикновено POM в Selenium Тестов случай
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")); }
В какво е Page Factory Selenium?
Page Factory в Selenium е вградена концепция за рамка на Page Object Model за Selenium WebDriver, но е много оптимизиран. Използва се за инициализация на обекти Page или за инстанциране на самия обект Page. Използва се и за инициализиране на елементи от клас на страница без използване на „FindElement/s“.
Тук също следваме концепцията за разделяне на Page Object Repository и Test Methods. Освен това, с помощта на клас PageFactory в Selenium, използваме анотации @FindBy за да намерите WebElement. Използваме метода initElements за инициализиране на уеб елементи
@FindBy може да приеме tagName, partialLinkText, име, 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 с фабрика за страници
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 TestCase с концепция 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. Използва се за намиране на уеб елементи само когато елементите се използват в някаква операция. Той присвоява таймаут за WebElements на класа страница на обекта. Едно от ключовите предимства на използването на модела PageFactory в Selenium е AjaxElementLocatorFactory клас.
Тук, когато се извърши операция върху елемент, изчакването за неговата видимост започва само от този момент. Ако елементът не бъде намерен в дадения интервал от време, Тестов случай изпълнението ще хвърли изключение „NoSuchElementException“.
Oбобщение
- Page Object Model in Selenium WebDriver е шаблон за проектиране на обектно хранилище.
- Selenium обектният модел на страницата създава нашия код за тестване, който може да се поддържа и използва повторно.
- Page Factory е оптимизиран начин за създаване на хранилище на обекти в концепцията на рамката на Page Object Model.
- AjaxElementLocatorFactory е концепция за отложено зареждане в Page Factory – шаблон за проектиране на обект на страница за идентифициране на WebElements само когато се използват в която и да е операция.
Изтеглете Selenium Проектни файлове за демонстрацията в този урок