Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >聊聊UI自动化的PageObject设计模式

聊聊UI自动化的PageObject设计模式

作者头像
互联网金融打杂
发布于 2022-05-09 13:52:10
发布于 2022-05-09 13:52:10
77700
代码可运行
举报
运行总次数:0
代码可运行

当我们开发UI自动化测试用例时,需要引用页面中的元素(数据)才能够进行点击(动作)并显示出页面内容。如果我们开发的用例是直接对HTML元素进行操作,则这样的用例无法“应对”页面中UI的更改。

PageObject模式就是对HTML页面以及元素细节的封装,并对外提供应用级别的API,使你摆脱与HTML的纠缠。 

什么是PageObject模型?

PageObject模型是一种设计模式,其核心是减少代码重复(最小化代码更新/维护用例)以降低用例开发的工作量。利用PageObject模型,为每个网页创建Page类,测试场景中用的定位器/元素存储在单独的类文件中,并且测试用例在不同的文件中,使代码更加模块化。由于元素定位器和测试脚本是分开存储的,因此对 Web UI 元素的任何更改只需要在测试场景代码中进行更改即可。

基于PageObject模型的实现包含以下两点:

  • Page类——将页面封装成 Page 类,页面元素为 Page 类的成员元素,页面功能放在 Page 类方法里。
  • 测试类——针对这个 Page 类定义一个测试类,在测试类调用 Page 类的各个类方法完成测试。它使用Page类中的页面方法/方法与页面的 UI 元素进行交互。如果网页的UI有变化,只需要更新Page类,测试类无需改动。

为什么使用PageObject模型?

随着项目新需求的不断迭代,开发代码和测试代码的复杂性增加。因此,开发自动化测试代码时必须遵循正确的项目结构。否则,代码可能会变得难以维护。

  1. Web由各种 WebElement(例如,菜单项、文本框、复选框、单选按钮等)的不同网页组成。测试用例与这些元素交互,如果Selenium 定位器没有以正确的方式管理,代码的复杂性将成倍增加。
  2. 测试代码的重复或定位器的重复使用会降低代码的可读性,从而导致代码维护的开销成本增加。例如,测试电子商务网站的登录功能,我们使用Selenium进行自动化测试,测试代码可以与网页的底层 UI 或定位器进行交互。如果修改了UI或该页面上元素的路径发生了变化,会发生什么情况?自动化测试用例将失败,因为该用例执行的过程在网页上找不到依赖的页面元素。如果你对所有网页采用相同的测试开发方法。在这种情况下,测试者必须花费大量精力来即时更新分散在不同页面中的定位器。

PO模式优点

PageObject模型的优点

现在大家已经了解了PageObject设计模式的基础知识,让我们来看看使用该设计模式的一些优点:

  • 提高可重用性——不同 POM 类中的PageObject方法可以在不同的测试用例/测试套件中重用。因此,由于页面方法的可重用性增加,整体代码量将大大减少。
  • 提升可维护性——由于测试场景和定位器是分开存储的,它使代码更清晰,并且在维护测试代码上花费的精力更少。
  • 降低UI更改对用例造成的影响——即使 UI 中经常发生更改,也只需要在对象存储库(存储定位器)中进行更改,对测试场景几乎没有影响。
  • 便与多个测试框架集成——由于测试实现与PageObject的存储库分离,我们可以将相同的存储库与不同的测试框架一起使用。例如,Test Case-1可以使用 Robot 框架,Tese Case - 2 可以使用 pytest 框架等,单个测试套件可以包含使用不同测试框架实现的测试用例。

PageObject实践

首先我们先看一个反例,一个不使用PageObject模式的自动化测试示例(测试用户登录场景):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/***
* Tests login feature
*/
public class Login {

public void testLogin() {
// fill login data on sign-in page
driver.findElement(By.name("user_name")).sendKeys("userName");
driver.findElement(By.name("password")).sendKeys("my supersecret password");
driver.findElement(By.name("sign-in")).click();

// verify h1 tag is "Hello userName" after login
driver.findElement(By.tagName("h1")).isDisplayed();
assertThat(driver.findElement(By.tagName("h1")).getText(), is("Hello userName"));
}
}

这种写法有两个问题:

  • 测试用例和 AUT 的定位器没有分离,两者耦合在一起。如果AUT的UI更改布局或登录的输入和处理方式,则用例本身必须更改。
  • 如果多个页面都需要登录,则定位器将分布在多个测试用例中。

使用PageObject模式,测试方法(登录)写法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

/**
* Page Object encapsulates the Sign-in page.
*/
public class SignInPage {
protected WebDriver driver;

// <input name="user_name" type="text" value="">
private By usernameBy = By.name("user_name");
// <input name="password" type="password" value="">
private By passwordBy = By.name("password");
// <input name="sign_in" type="submit" value="SignIn">
private By signinBy = By.name("sign_in");

public SignInPage(WebDriver driver){
this.driver = driver;
}

/**
* Login as valid user
*
* @param userName
* @param password
* @return HomePage object
*/
public HomePage loginValidUser(String userName, String password) {
driver.findElement(usernameBy).sendKeys(userName);
driver.findElement(passwordBy).sendKeys(password);
driver.findElement(signinBy).click();
return new HomePage(driver);
}
}

用户登录以后的元素定位(用于断言)方法写法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

/**
* Page Object encapsulates the Home Page
*/
public class HomePage {
protected WebDriver driver;

// <h1>Hello userName</h1>
private By messageBy = By.tagName("h1");

public HomePage(WebDriver driver){
this.driver = driver;
if (!driver.getTitle().equals("Home Page of logged in user")) {
throw new IllegalStateException("This is not Home Page of logged in user," +
" current page is: " + driver.getCurrentUrl());
}
}

/**
* Get message (h1 tag)
*
* @return String message text
*/
public String getMessageText() {
return driver.findElement(messageBy).getText();
}

public HomePage manageProfile() {
// Page encapsulation to manage profile functionality
return new HomePage(driver);
}
/* More methods offering the services represented by Home Page
of Logged User. These methods in turn might return more Page Objects
for example click on Compose mail button could return ComposeMail class object */
}

登录测试用例使用上述两个PageObject,如下所示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/***
* Tests login feature
*/
public class TestLogin {

@Test
public void testLogin() {
SignInPage signInPage = new SignInPage(driver);
/// login
HomePage homePage = signInPage.loginValidUser("userName", "password");
// assert login result
assertThat(homePage.getMessageText(), is("Hello userName"));
}

}

注意事项

从上述例子中,可以看出PageObject的设计方式有很大的灵活性,这里也总结一下使用PageObject开发用例的注意事项:

  1. PageObject本身不进行断言。断言是测试用例的一部分,应该始终包含在测试代码中,即与测试内容相关的代码不应包含在PageObject中。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void testMessagesAreReadOrUnread() {
Inbox inbox = new Inbox(driver);
inbox.assertMessageWithSubjectIsUnread("I like cheese");
inbox.assertMessageWithSubjectIsNotUnread("I'm not fond of tofu");
}

 

应该重写为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void testMessagesAreReadOrUnread() {
Inbox inbox = new Inbox(driver);
assertTrue(inbox.isMessageWithSubjectIsUnread("I like cheese"));
assertFalse(inbox.isMessageWithSubjectIsUnread("I'm not fond of tofu"));
}
  1. 单一的验证可以包含在PageObject内,即验证页面以及页面上的关键元素是否正确加载,且此验证应在实例化PageObject时完成。在上面的示例中, HomePage 构造函数检查预期页面是否加载完毕以执行测试代码。

附:以PageObject模式开发的完整的登录场景代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class LoginPage {
private final WebDriver driver;

public LoginPage(WebDriver driver) {
this.driver = driver;

// Check that we're on the right page.
if (!"Login".equals(driver.getTitle())) {
// Alternatively, we could navigate to the login page, perhaps logging out first
throw new IllegalStateException("This is not the login page");
}
}

// The login page contains several HTML elements that will be represented as WebElements.
// The locators for these elements should only be defined once.
By usernameLocator = By.id("username");
By passwordLocator = By.id("passwd");
By loginButtonLocator = By.id("login");

// The login page allows the user to type their username into the username field
public LoginPage typeUsername(String username) {
// This is the only place that "knows" how to enter a username
driver.findElement(usernameLocator).sendKeys(username);

// Return the current page object as this action doesn't navigate to a page represented by another PageObject
return this;
}

// The login page allows the user to type their password into the password field
public LoginPage typePassword(String password) {
// This is the only place that "knows" how to enter a password
driver.findElement(passwordLocator).sendKeys(password);

// Return the current page object as this action doesn't navigate to a page represented by another PageObject
return this;
}

// The login page allows the user to submit the login form
public HomePage submitLogin() {
// This is the only place that submits the login form and expects the destination to be the home page.
// A seperate method should be created for the instance of clicking login whilst expecting a login failure.
driver.findElement(loginButtonLocator).submit();

// Return a new page object representing the destination. Should the login page ever
// go somewhere else (for example, a legal disclaimer) then changing the method signature
// for this method will mean that all tests that rely on this behaviour won't compile.
return new HomePage(driver);
}

// The login page allows the user to submit the login form knowing that an invalid username and / or password were entered
public LoginPage submitLoginExpectingFailure() {
// This is the only place that submits the login form and expects the destination to be the login page due to login failure.
driver.findElement(loginButtonLocator).submit();

// Return a new page object representing the destination. Should the user ever be navigated to the home page after submiting a login with credentials
// expected to fail login, the script will fail when it attempts to instantiate the LoginPage PageObject.
return new LoginPage(driver);
}

// Conceptually, the login page offers the user the service of being able to "log into"
// the application using a user name and password.
public HomePage loginAs(String username, String password) {
// The PageObject methods that enter username, password & submit login have already defined and should not be repeated here.
typeUsername(username);
typePassword(password);
return submitLogin();
}
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
PageObject(PO)设计模式在 UI 自动化中的实践总结(以 QQ 邮箱登陆为例)
https://martinfowler.com/bliki/PageObject.html
霍格沃兹测试开发
2020/11/17
1.1K0
Selenium-PO设计模式
PO(page object)设计模式是在自动化中已经流行起来的一种易于维护和减少代码的设计模式。在自动化测试中,PO对象作为一个与页面交互的接口。测试中需要与页面的UI进行交互时,便调用PO的方法。这样做的好处是,如果页面的UI发生了更改,那么测试用例本身不需要更改,只需更改PO中的代码即可。
wangmcn
2023/01/05
5600
Selenium中Page Object设计模式
Page Object(页面对象)模式,是Selenium实战中最为流行,并且被做自动化测试同学所熟悉和推崇的一种设计模式之一。在设计测试时,把页面元素定位和元素操作方法按照页面抽象出来,分离成一定的对象,然后再进行组织。
软件测试君
2019/08/22
1.9K0
selenium python面试题_selenium面试题
selenium中没有提供原生的方法判断元素是否存在,一般我们可以通过定位元素+异常捕获的方式判断。
全栈程序员站长
2022/06/24
8310
自动化测试-[译]PageObject设计模式
原文链接:https://martinfowler.com/bliki/PageObject.html
无辛
2021/08/13
6650
自动化测试-[译]PageObject设计模式
WebDriver自动化项目设计模式快速入门-自动化测试系列笔记
朵拉小序:Page Object,即”页面对象“,就是将单个页面作为一个对象来处理。 以面向对象的方式来处理页面和业务流程的好处在于,如果某个页面元素的属性有了变化,只需在包含这个元素的页面对象中调整操作该元素的属性或方法即可。 若有大量重复代码,且开发修改一个页面的一个元素属性后,那自动化测试需要修改调整的工作量会 成倍增加。 解决这种问题,可采用面向对象的方式来处理页面之间的交互。将单个页面上的页面元素和相应操作封装到一个页面对象中。即Page Object。 一、page Object 首先,明
企鹅号小编
2018/02/24
7120
WebDriver自动化项目设计模式快速入门-自动化测试系列笔记
Selenium PageObject设计模式
Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化,只需要调整页面元素封装的代码,提高测试用例的可维护性。
清风穆云
2021/08/09
3090
Python+Selenium自动化测试:Page Object模式
Page Objects是selenium的一种测试设计模式,主要将每个页面看作是一个class。class的内容主要包括属性和方法,属性不难理解,就是这个页面中的元素对象,比如输入用户名的输入框,输入登陆密码的输入框、登陆按钮、这个页面的url等。而方法,主要是指这个页面可以提供的具体功能。
测试开发技术
2021/08/20
1.2K0
自动化测试:如何构建Selenium框架-云层补充版
云层:Selenium在某些角度已经是一个淘汰的技术了,但是并不妨碍大家重新看这篇文章来整下UI自动化框架实践体系。
TestOps
2022/04/07
2.9K0
自动化测试:如何构建Selenium框架-云层补充版
WebUI 自动化测试的经典设计模式:PO
先来看下未使用 PO(PageObject) 设计模式下的代码,以网页版百度登录为例来说明。
Wu_Candy
2022/07/04
1.1K0
Selenium的PO模式(Page Object Model)[python版]
首先,我们要分离测试对象(元素对象)和测试脚本(用例脚本),那么我们分别创建两个脚本文件, LoginPage.py 用于定义页面元素对象,每一个元素都封装成组件(可以看做存放页面元素对象的仓库)  CaseLoginTest.py 测试用例脚本。我们的实现思想,一切元素和元素的操作组件化定义在Page页面,用例脚本页面,通过调用Page中的组件对象,进行拼凑成一个登录脚本。
流柯
2018/08/31
1.6K0
如何对使用React和EMF parsley设计的Web UI应用程序进行测试自动化
Web UI应用程序是指通过Web浏览器访问的应用程序,它们通常具有复杂的用户界面和交互逻辑。为了确保Web UI应用程序的功能、性能和用户体验,测试自动化是一种有效的方法,它可以在不需要人工干预的情况下,快速地执行重复的测试任务,并提供可靠的测试结果。本文将介绍如何对使用React和EMF parsley设计的Web UI应用程序进行测试自动化,以及使用HtmlUnitDriver和java代码实现的示例。
jackcode
2023/07/28
3520
如何对使用React和EMF parsley设计的Web UI应用程序进行测试自动化
一篇文章学会PageFactory模式
我们已经学习了Page Object设计模式,优势很明显,能更好的体现java的面向对象思想和封装特性。但同时也存在一些不足之处,那就是随着这种模式使用,随着元素定位获取,元素定位与页面操作方法都在一个类里维护,会造成代码冗余度过高。
软件测试君
2019/08/29
2.2K0
Selenium 自动化综合实践
无头浏览器即headless browser,是一种没有界面的浏览器。既然是浏览器那么浏览器该有的东西它都应该有,只是看不到界面而已。
清风穆云
2021/08/09
3850
Java自动化测试(web自动化测试框架 28)
http://120.78.128.25:8765/Admin/Index/login.html
zx钟
2020/09/14
2.5K0
【项目测试】博客系统—Selenium自动化测试、编写测试用例
什么是UI测试呢——全称是用户界面测试(User Interface Testing)
三三是该溜子
2025/02/26
1950
【项目测试】博客系统—Selenium自动化测试、编写测试用例
Selenium4+Python3系列(十) - Page Object设计模式
Page Object(PO)模式,是Selenium实战中最为流行,并且被自动化测试同学所熟悉和推崇的一种设计模式之一。在设计测试时,把页面元素定位和元素操作方法按照页面抽象出来,分离成一定的对象,然后再进行组织。
软件测试君
2022/12/05
4800
Selenium4+Python3系列(十) -  Page Object设计模式
Selenium编写自动化用例的8种技巧
在开始自动化时,您可能会遇到各种可能包含在自动化代码中的方法,技术,框架和工具。有时,与提供更好的灵活性或解决问题的更好方法相比,这种多功能性导致代码更加复杂。在编写自动化代码时,重要的是我们能够清楚地描述自动化测试的目标以及我们如何实现它。话虽如此,编写“干净的代码”以提供更好的可维护性和可读性很重要。编写干净的代码也不是一件容易的事,您需要牢记许多最佳实践。以下主题突出显示了编写更好的自动化代码应获得的8条银线。
FunTester
2019/11/04
1.3K0
您需要了解的有关Selenium等待方法
等待可以帮助用户在重定向到其他网页时解决问题。这可以通过刷新整个网页并重新加载新的Web元素来实现。有时,也可能会有Ajax调用。因此,在重新加载网页并反映Web元素时可以看到时间滞后。
用户7466307
2020/06/24
1.9K0
自动化测试如此容易!多语言自动化测试框架 Selenium 编程(C#篇)
Selenium 是功能强大的自动化测试工具集,是支持 Web 浏览器自动化的一系列工具和库的总括项目,一共包括以下三个项目:
痴者工良
2023/03/11
4.1K0
自动化测试如此容易!多语言自动化测试框架 Selenium 编程(C#篇)
推荐阅读
相关推荐
PageObject(PO)设计模式在 UI 自动化中的实践总结(以 QQ 邮箱登陆为例)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验