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 元素用于任何操作时才识别它们。