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().

Sideobjektmodell

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

Sideobjektmodell

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.

Sideobjektmodell

Fordeler med POM

  1. 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å.
  2. 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.
  3. Koden blir mindre og optimalisert på grunn av de gjenbrukbare sidemetodene i POM-klassene.
  4. 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.

Implementer POM

Komplett eksempel

Testforsøk: Gå til Guru99 Demo Site.

Trinn 1) Gå til Guru99 Demo Site

Implementer POM

Trinn 2) Sjekk teksten "Guru99 Bank" på hjemmesiden

Implementer POM

Trinn 3) Logg på applikasjonen

Implementer POM

Trinn 4) Bekreft at hjemmesiden inneholder tekst som "Manger Id: demo"

Implementer POM

Her har vi å gjøre med 2 sider

  1. Påloggingssiden
  2. 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

Page Factory In Selenium

@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:

Page Factory i Selenium

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.

AjaxElement Locator Factory

Oppsummering

  1. Sideobjektmodell i Selenium WebDriver er et designmønster for objektlager.
  2. Selenium sideobjektmodell lager vår testkode som kan vedlikeholdes, gjenbrukes.
  3. Page Factory er en optimalisert måte å lage objektlager i Page Object Model-rammekonseptet.
  4. 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