Modelo de objeto de página (POM) e fábrica de páginas em Selenium

O que é o modelo de objeto de página?

Modelo de objeto de página (POM) é um padrão de design, popularmente usado em automação de testes que cria repositório de objetos para elementos de UI da web. A vantagem do modelo é que ele reduz a duplicação de código e melhora a manutenção dos testes.

Nesse modelo, para cada página da web no aplicativo, deve haver uma classe de página correspondente. Esta classe Page identificará os WebElements dessa página da web e também contém métodos Page que executam operações nesses WebElements. O nome desses métodos deve ser fornecido de acordo com a tarefa que estão executando, ou seja, se um carregador estiver aguardando o aparecimento do gateway de pagamento, o nome do método POM pode ser waitForPaymentScreenDisplay().

Modelo de objeto de página

Por que modelo de objeto de página?

Iniciar uma UI Automation no Selenium WebDriver NÃO é uma tarefa difícil. Você só precisa encontrar os elementos e realizar operações neles.

Considere este script simples para fazer login em um site

Modelo de objeto de página

Como você pode observar, tudo o que estamos fazendo é encontrar elementos e preencher valores para esses elementos.

Este é um pequeno script. A manutenção do script parece fácil. Mas com o tempo o conjunto de testes crescerá. À medida que você adiciona mais e mais linhas ao seu código, as coisas ficam difíceis.

O principal problema com a manutenção de scripts é que se 10 scripts diferentes estiverem usando o mesmo elemento de página, com qualquer alteração nesse elemento, você precisará alterar todos os 10 scripts. Isso consome tempo e está sujeito a erros.

Uma abordagem melhor para a manutenção de scripts é criar um arquivo de classe separado que encontre elementos da web, preencha-os ou verifique-os. Esta classe pode ser reutilizada em todos os scripts que utilizam esse elemento. Futuramente, se houver uma alteração no elemento web, precisaremos fazer a alteração em apenas 1 arquivo de classe e não em 10 scripts diferentes.

Essa abordagem é chamada de modelo de objeto de página no Selenium. Ajuda a tornar o código mais legível, sustentável e reutilizável.

Modelo de objeto de página

Vantagens do POM

  1. O Page Object Design Pattern diz que as operações e fluxos na IU devem ser separados da verificação. Este conceito torna nosso código mais limpo e fácil de entender.
  2. O segundo benefício é que o repositório de objetos é independente de casos de teste, portanto, podemos usar o mesmo repositório de objetos para uma finalidade diferente com ferramentas diferentes. Por exemplo, podemos integrar o Page Object Model no Selenium com TestNG/JUnit para funcionalidade ensaio e ao mesmo tempo com JBehave/Cucumber para testes de aceitação.
  3. O código fica menor e otimizado por causa dos métodos de página reutilizáveis ​​nas classes POM.
  4. Os métodos obtêm nomes mais realistas que podem ser facilmente mapeados com a operação acontecendo na UI. ou seja, se depois de clicar no botão chegarmos à página inicial, o nome do método será como 'gotoHomePage()'.

Como implementar o POM?

POM simples:

É a estrutura básica do modelo de objeto de página onde todos os elementos da Web do AUT e o método que opera nesses elementos da Web são mantidos dentro de um arquivo de classe. Uma tarefa como verificação deve ser separada como parte dos métodos de teste.

Implementar POM

Exemplo Completo

Caso de teste: Vá para o site de demonstração Guru99.

Etapa 1) Vá para o site de demonstração Guru99

Implementar POM

Etapa 2) Na página inicial, verifique se o texto “Guru99 Bank” está presente

Implementar POM

Etapa 3) Faça login no aplicativo

Implementar POM

Etapa 4) Verifique se a página inicial contém texto como “Manger Id: demo”

Implementar POM

Aqui estamos lidando com 2 páginas

  1. Página de login
  2. Página inicial (mostrada assim que você faz login)

Assim, criamos 2 POM nas classes Selenium

Página de login do 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 Home Page POM em 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 simples em caso de teste 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"));

    }

O que é Page Factory no Selenium?

Fábrica de páginas em Selenium é um conceito de estrutura de modelo de objeto de página integrado para Selenium WebDriver, mas é muito otimizado. É usado para inicialização de objetos Page ou para instanciar o próprio objeto Page. Também é usado para inicializar elementos da classe Page sem usar “FindElement/s”.

Aqui também seguimos o conceito de separação entre repositório de objetos de página e métodos de teste. Além disso, com a ajuda da classe PageFactory no Selenium, usamos anotações @FindBy para encontrar WebElement. Usamos o método initElements para inicializar elementos da web

Fábrica de páginas em Selenium

@FindBy pode aceitar tagName, parcialLinkText, nome, linkText, id, css, className, xpath como atributos.

Vejamos o mesmo exemplo acima usando Page Factory

Página de login do Guru99 com 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();           

    }

}

Página inicial do Guru99 com fábrica de páginas

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 com conceito 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"));

    }

}

A estrutura completa do projeto será semelhante ao diagrama:

Fábrica de páginas em Selenium

AjaxElementLocatorFactory

AjaxElementLocatorFactory é um conceito de carregamento lento do PageFactory no Selenium. É usado para localizar os elementos da web somente quando os elementos são usados ​​em alguma operação. Ele atribui um tempo limite para WebElements à classe de página do objeto. Uma das principais vantagens de usar o padrão PageFactory no Selenium é a classe AjaxElementLocatorFactory.

Aqui, quando uma operação é realizada em um elemento a espera pela sua visibilidade começa apenas a partir desse momento. Se o elemento não for encontrado no intervalo de tempo determinado, Caso de teste a execução lançará a exceção 'NoSuchElementException'.

Fábrica de localizadores AjaxElement

Resumo

  1. O modelo de objeto de página no Selenium WebDriver é um padrão de design de repositório de objetos.
  2. O modelo de objeto de página Selenium cria nosso código de teste sustentável e reutilizável.
  3. Page Factory é uma maneira otimizada de criar repositório de objetos no conceito de estrutura do Page Object Model.
  4. AjaxElementLocatorFactory é um conceito de carregamento lento no Page Factory – padrão de design de objeto de página para identificar WebElements apenas quando eles são usados ​​em qualquer operação.

Baixe os arquivos do projeto Selenium para a demonstração neste tutorial