页面对象模型和工厂 Selenium

什么是页面对象模型?

页面对象模型 (POM) 是一种设计模式,常用于测试自动化,为 Web UI 元素创建对象存储库。该模型的优点是减少代码重复并改善测试维护。

在此模型下,对于应用程序中的每个网页,都应该有一个相应的 Page 类。此 Page 类将标识该网页的 WebElement,还包含对这些 WebElement 执行操作的 Page 方法。这些方法的名称应根据它们正在执行的任务来指定,即,如果加载器正在等待支付网关出现,则 POM 方法名称可以是 waitForPaymentScreenDisplay()。

页面对象模型

为什么选择页面对象模型?

在中启动 UI 自动化 Selenium WebDriver 不是一项艰巨的任务。你只需要找到元素,然后对其执行操作。

考虑使用这个简单的脚本来登录网站

页面对象模型

正如您所看到的,我们所做的就是查找元素并为这些元素填充值。

这是一个小脚本。脚本维护看起来很容易。但随着时间的推移,测试套件会增长。随着您在代码中添加越来越多的行,事情会变得困难。

脚本维护的主要问题是,如果 10 个不同的脚本使用同一个页面元素,那么一旦该元素发生任何变化,您就需要更改所有 10 个脚本。这非常耗时,而且容易出错。

维护脚本的更好方法是创建一个单独的类文件,该文件将查找 Web 元素、填充它们或验证它们。该类可以在使用该元素的所有脚本中重复使用。将来,如果 Web 元素发生变化,我们只需在 1 个类文件中进行更改,而不是 10 个不同的脚本。

这种方法在 Selenium.它有助于使代码更具可读性、可维护性和可重用性。

页面对象模型

POM的优点

  1. 页面对象设计模式认为 UI 中的操作和流程应该与验证分开。这个概念使我们的代码更简洁、更易于理解。
  2. 第二个好处是对象存储库独立于测试用例,因此我们可以使用不同的工具将同一个对象存储库用于不同的目的。例如,我们可以将页面对象模型集成到 Selenium - TestNG/JUnit 功能性 测试与验证 同时与 JBehave/Cucumber 进行验收测试。
  3. 由于 POM 类中可重用的页面方法,代码变得更少且更优化。
  4. 方法获得了更为现实的名称,可以轻松地与 UI 中发生的操作进行映射。例如,如果单击按钮后我们进入主页,则方法名称将类似于“gotoHomePage()”。

如何实现POM?

简单POM:

它是页面对象模型框架的基本结构,其中 AUT 并且对这些 Web 元素进行操作的方法在类文件中维护。像验证这样的任务应该作为测试方法的一部分分离出来。

实施 POM

完整示例

测试用例: 前往 Guru99 演示站点。

步骤 1) 前往 Guru99 演示网站

实施 POM

步骤 2)在主页上检查文本“Guru99 Bank”是否存在

实施 POM

步骤 3)登录应用程序

实施 POM

步骤 4)验证主页是否包含文本“Manger Id: demo”

实施 POM

我们正在处理 2 页

  1. 登录页面
  2. 主页(登录后显示)

因此,我们在 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("https://demo.guru99.com/V4/");

    }

    /**

     * This test case will login in https://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?

页面工厂 Selenium 是内置的页面对象模型框架概念 Selenium WebDriver,但它非常优化。它用于初始化 Page 对象或实例化 Page 对象本身。它还用于初始化 Page 类元素,而无需使用“FindElement/s”。

在这里,我们也遵循了页面对象存储库和测试方法分离的概念。此外,借助 Selenium,我们使用注释 @FindBy 找到 WebElement。我们使用 initElements 方法来初始化 Web 元素

页面工厂 Selenium

@FindBy 可以接受 标签名称、部分链接文本、名称、链接文本、id、css、类名称、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();

        }

}

带有 Page Factory 概念的 Guru99 TestCase

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("https://demo.guru99.com/V4/");

    }

    /**

     * This test go to https://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

AjaxElementLocatorFactory

AjaxElementLocatorFactory 是 PageFactory 中的延迟加载概念 Selenium。它仅用于在任何操作中使用元素时查找 Web 元素。它为对象页面类分配 WebElements 的超时时间。在 Selenium 是 AjaxElementLocatorFactory 类。

在这里,当对元素执行操作时,等待其可见性仅从那一刻开始。如果在给定的时间间隔内未找到该元素, 测试用例 执行会抛出‘NoSuchElementException’异常。

AjaxElement 定位器工厂

结语

  1. 页面对象模型 Selenium WebDriver 是一种对象存储库设计模式。
  2. Selenium 页面对象模型使我们的测试代码可维护、可重用。
  3. Page Factory 是在页面对象模型框架概念中创建对象存储库的一种优化方法。
  4. AjaxElementLocatorFactory 是 Page Factory 中的一个延迟加载概念——页面对象设计模式,仅在任何操作中使用 WebElements 时才识别它们。

下载 Selenium 本教程中演示的项目文件