Selenium 中的页面对象模型与工厂
什么是页面对象模型?
页面对象模型 (POM) 是一种设计模式,在测试自动化中广泛使用,它为 web UI 元素创建对象库。该模型的优点是减少了代码重复并提高了测试维护性。
在此模型下,应用程序中的每个网页都应该有一个相应的页面类。此页面类将识别该网页的 WebElements,并且还包含对这些 WebElements 执行操作的页面方法。这些方法的名称应根据它们执行的任务来命名,即,如果加载程序正在等待支付网关出现,则 POM 方法名称可以是 waitForPaymentScreenDisplay()。
为什么使用页面对象模型?
在 Selenium WebDriver 中启动 UI 自动化并非难事。你只需找到元素,然后对其执行操作即可。
考虑下面这个简单的脚本来登录网站
正如你所观察到的,我们所做的只是查找元素并为这些元素填充值。
这是一个小脚本。脚本维护看起来很简单。但随着时间的推移,测试套件会增长。随着代码中添加的行越来越多,事情变得越来越困难。
脚本维护的主要问题是,如果 10 个不同的脚本使用同一个页面元素,那么该元素的任何更改都需要更改所有 10 个脚本。这既耗时又容易出错。
一种更好的脚本维护方法是创建一个单独的类文件,该文件将查找 web 元素、填充它们或验证它们。该类可以在所有使用该元素的脚本中重复使用。将来,如果 web 元素发生变化,我们只需要更改 1 个类文件,而不是 10 个不同的脚本。
这种方法在 Selenium 中称为页面对象模型。它有助于使代码更具可读性、可维护性和可重用性。
POM 的优势
- 页面对象设计模式指出 UI 中的操作和流程应与验证分离。这个概念使我们的代码更清晰易懂。
- 第二个好处是对象存储库独立于测试用例,因此我们可以将相同的对象存储库用于不同工具的不同目的。例如,我们可以将 Selenium 中的页面对象模型与 TestNG/JUnit 集成用于功能测试,同时与 JBehave/Cucumber 集成用于验收测试。
- 由于 POM 类中可重用的页面方法,代码变得更少且更优化。
- 方法获得了更逼真的名称,可以轻松地与 UI 中发生的操作进行映射。例如,如果单击按钮后我们进入主页,方法名称将类似于“gotoHomePage()”。
如何实现 POM?
简单的 POM
这是页面对象模型框架的基本结构,其中 AUT 的所有 Web 元素以及对这些 Web 元素进行操作的方法都维护在一个类文件中。验证等任务应作为测试方法的一部分单独进行。
完整示例
测试用例:访问 Guru99 演示站点。
步骤 1) 访问 Guru99 演示站点
步骤 2) 在主页中检查文本“Guru99 Bank”是否存在
步骤 3) 登录应用程序
步骤 4) 验证主页是否包含文本“经理 ID:demo”
这里我们正在处理 2 个页面
- 登录页面
- 主页(登录后显示)
因此,我们在 Selenium 中创建 2 个 POM 类
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();
}
}
Selenium 中的 Guru99 主页 POM
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();
}
}
Selenium 测试用例中的 Guru99 简单 POM
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"));
}
Selenium 中的 Page Factory 是什么?
Selenium 中的 Page Factory 是 Selenium WebDriver 的内置页面对象模型框架概念,但它非常优化。它用于初始化页面对象或实例化页面对象本身。它还用于在不使用“FindElement/s”的情况下初始化页面类元素。
在这里,我们同样遵循页面对象库和测试方法分离的概念。此外,借助 Selenium 中的 PageFactory 类,我们使用注解 @FindBy 来查找 WebElement。我们使用 initElements 方法来初始化 web 元素
@FindBy 可以接受 tagName、partialLinkText、name、linkText、id、css、className、xpath 作为属性。
让我们使用 Page Factory 来看上面的同一个例子
使用 Page Factory 的 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 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();
}
}
使用 Page Factory 的 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 使用 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("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"));
}
}
完整的项目结构将如下图所示
AjaxElementLocatorFactory
AjaxElementLocatorFactory 是 Selenium 中 PageFactory 的延迟加载概念。它仅在元素用于任何操作时才用于查找 web 元素。它为对象页面类中的 WebElements 分配超时。使用 Selenium 中 PageFactory 模式的主要优势之一是 AjaxElementLocatorFactory 类。
在这里,当对元素执行操作时,其可见性的等待仅从那一刻开始。如果在给定时间间隔内未找到元素,测试用例执行将抛出“NoSuchElementException”异常。
摘要
- Selenium WebDriver 中的页面对象模型是一种对象存储库设计模式。
- Selenium 页面对象模型使我们的测试代码可维护、可重用。
- Page Factory 是一种优化方法,用于在页面对象模型框架概念中创建对象存储库。
- AjaxElementLocatorFactory 是 Page Factory 页面对象设计模式中的一个延迟加载概念,仅在 Web 元素用于任何操作时才识别它们。











