Page Object Model (POM) & Page Factory i Selenium
Hva er sideobjektmodell?
Sideobjektmodell (POM) er et designmønster, populært brukt i testautomatisering som lager Object Repository for web-UI-elementer. Fordelen med modellen er at den reduserer kodeduplisering og forbedrer testvedlikeholdet.
Under denne modellen, for hver nettside i applikasjonen, skal det være en tilsvarende sideklasse. Denne sideklassen vil identifisere webelementene til den nettsiden og inneholder også sidemetoder som utfører operasjoner på disse webelementene. Navn på disse metodene skal gis i henhold til oppgaven de utfører, dvs. hvis en laster venter på at betalingsgatewayen skal vises, kan POM-metodenavnet være waitForPaymentScreenDisplay().
Hvorfor sideobjektmodell?
Starte en UI-automatisering i Selenium WebDriver er IKKE en tøff oppgave. Du trenger bare å finne elementer, utføre operasjoner på det.
Vurder dette enkle skriptet for å logge inn på et nettsted
Som du kan se, er alt vi gjør å finne elementer og fylle ut verdier for disse elementene.
Dette er et lite manus. Skriptvedlikehold ser enkelt ut. Men med tiden vil testsuiten vokse. Etter hvert som du legger til flere og flere linjer i koden din, blir ting vanskelig.
Hovedproblemet med skriptvedlikehold er at hvis 10 forskjellige skript bruker det samme sideelementet, med enhver endring i det elementet, må du endre alle 10 skriptene. Dette er tidkrevende og utsatt for feil.
En bedre tilnærming til vedlikehold av skript er å lage en egen klassefil som kan finne nettelementer, fylle dem eller verifisere dem. Denne klassen kan gjenbrukes i alle skriptene som bruker det elementet. I fremtiden, hvis det er en endring i webelementet, må vi gjøre endringen i bare 1 klassefil og ikke 10 forskjellige skript.
Denne tilnærmingen kalles Page Object Model i Selenium. Det bidrar til å gjøre koden mer lesbar, vedlikeholdbar og gjenbrukbar.
Fordeler med POM
- Page Object Design Pattern sier at operasjoner og flyter i brukergrensesnittet skal skilles fra verifisering. Dette konseptet gjør koden vår renere og enkel å forstå.
- Den andre fordelen er at objektlageret er uavhengig av testtilfeller, så vi kan bruke det samme objektlageret til et annet formål med forskjellige verktøy. For eksempel kan vi integrere Page Object Model i Selenium med TestNG/JUnit for funksjonell Testing og samtidig med JBehave/Cucumber for akseptansetesting.
- Koden blir mindre og optimalisert på grunn av de gjenbrukbare sidemetodene i POM-klassene.
- Metoder får mer realistiske navn som enkelt kan kartlegges med operasjonen som skjer i brukergrensesnittet. dvs. hvis vi lander på hjemmesiden etter å ha klikket på knappen, vil metodenavnet være som 'gotoHomePage()'.
Hvordan implementere POM?
Enkel POM:
Det er den grunnleggende strukturen til sideobjektmodellrammeverket der alle webelementene i AUT og metoden som opererer på disse webelementene opprettholdes i en klassefil. En oppgave som verifisering bør være separat som en del av testmetoder.
Komplett eksempel
Testforsøk: Gå til Guru99 Demo Site.
Trinn 1) Gå til Guru99 Demo Site
Trinn 2) Sjekk teksten "Guru99 Bank" på hjemmesiden
Trinn 3) Logg på applikasjonen
Trinn 4) Bekreft at hjemmesiden inneholder tekst som "Manger Id: demo"
Her har vi å gjøre med 2 sider
- Påloggingssiden
- Hjemmeside (vises når du logger på)
Følgelig lager vi 2 POM i Selenium klasser
Guru99 Innloggingsside 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 Hjemmeside POM in 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 Enkel POM inn Selenium Test tilfelle
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")); }
Hva er Page Factory i Selenium?
Page Factory i Selenium er et innebygd Page Object Model-rammekonsept for Selenium WebDriver, men den er veldig optimalisert. Den brukes til initialisering av sideobjekter eller for å instansiere selve sideobjektet. Den brukes også til å initialisere sideklasseelementer uten å bruke "FindElement/s."
Også her følger vi konseptet med separasjon av Page Object Repository og testmetoder. I tillegg, ved hjelp av klassen PageFactory i Selenium, bruker vi merknader @FindBy for å finne WebElement. Vi bruker initElements-metoden for å initialisere webelementer
@FindBy kan godta tagName, partialLinkText, name, linkText, id, css, className, xpath som attributter.
La oss se på samme eksempel som ovenfor ved å bruke Page Factory
Guru99 Innloggingsside med 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 Hjemmeside med 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 TestCase med Page Factory-konsept
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")); } }
Komplett prosjektstruktur vil se ut som diagrammet:
AjaxElementLocatorFactory
AjaxElementLocatorFactory er et lat innlastingskonsept av PageFactory i Selenium. Den brukes til å finne nettelementene bare når elementene brukes i en operasjon. Den tildeler en tidsavbrudd for WebElements til objektsideklassen. En av de viktigste fordelene ved å bruke mønsteret PageFactory i Selenium er AjaxElementLocatorFactory Class.
Her, når en operasjon utføres på et element, starter ventetiden på dets synlighet fra det øyeblikket. Hvis elementet ikke blir funnet i det gitte tidsintervallet, Testsak kjøring vil gi 'NoSuchElementException' unntak.
Oppsummering
- Sideobjektmodell i Selenium WebDriver er et designmønster for objektlager.
- Selenium sideobjektmodell lager vår testkode som kan vedlikeholdes, gjenbrukes.
- Page Factory er en optimalisert måte å lage objektlager i Page Object Model-rammekonseptet.
- AjaxElementLocatorFactory er et lat innlastingskonsept i Page Factory – sideobjektdesignmønster for å identifisere WebElements bare når de brukes i enhver operasjon.
Last ned Selenium Prosjektfiler for demoen i denne opplæringen