Page Object 是 Selenium 自动化测试项目开发实践的最佳设计模式之一,Page Object 的主要体现于对界面交互细节的封装,这样可以使测试案例更关注与业务而非界面细节,提高测试案例的可读性。
1、认识 Paget Object
Page Object 设计模式的优点如下:
- 减少代码的重复;
- 提高测试用例的可读性;
- 提高测试用例的可维护性,特别是针对 UI 频繁变化的项目;
Paget Object 使用注意:
- public方法代表Page提供的功能
- 尽量不要暴露Page的内部细节
- 不要assertion
- 方法可以返回其他Page Objects
- Page Objects不用代表整个页面,可以是任意一个部分
- 一样的操作,不同的结果应该分开(正确登录,错误登录)
简单的说,Page Objects是指UI界面上用于与用户进行交互的对象。它可以指整个页面,也可以指Page上的某个区域。Page Objects是你的test code的交互对象,是对实际UI的一种抽象模型化。通过Page Objects可以减少重复代码的编写,例如,很多页面都有同样的header,footer,navigator等部分,如果对这些进行抽象,只写一次就可以在其他地方通用了。
当在为 Web 页面编写测试时,需要操作该 Web 页面上的元素进行操作。然而,如果在测试代码中直接操作 HTML 元素,那么你的代码是及其脆弱的,因为 UI 会经常变动。我们可以将一个 page 对象封装成一个 HTML 页面,可以通过提供的应用程序特定的 API 来操作页面元素,而不在 HTML 中四处搜寻。
page 对象的一个基本经验法则是,凡是人能做的事,page 对象通过软件客户端都能够做到。因此它也应当提供一个易于编程的接口并隐藏窗口中低层的部件。所以访问一个文本框应该通过一个访问方法(accessor method)来实现字符串的获取与返回,复选框应当使用布尔值,按钮应当被表示为行为导向的方法名。page 对象应当将在 GUI 控件上所有查询和操作数据的行为封装为方法。一个好的经验法则是,即使改变具体的控件,page 对象的接口也不应当发生变化。
尽管该术语是“页面”对象,但并不意味着需要针对每个页面建立一个这样的对象,例如页面有重要意义的元素可以独立为一个 page 对象。经验法则的目的在于通过给页面建模,从而对应用程序的使用者变得有意义。
2、Paget Object 实例
以 126 邮箱登录为例,通过 Page Object 设计模式来实现:
(1)首先创建 LoginPage.java 类
将登录界面LoginPage封装成对象;在包含主函数的类中直接调用;
分别定义了 126 邮箱首页的几个方法,用户名输入框,密码输入框,登录按钮;
package com.mypro.pom; import ...... public class LoginPage { private static WebElement element = null; public static WebElement login_UserName(WebDriver driver){ element = driver.findElement(By.id("idInput")); return element; } public static WebElement login_Password(WebDriver driver){ element = driver.findElement(By.id("pwdInput")); return element; } public static WebElement login_Button(WebDriver driver){ element = driver.findElement(By.id("loginBtn")); return element; } }
(2)创建 mailLogin.java 类
package com.mypro.pom.test; import ...... public class mailLogin { private static WebDriver driver = null; public static void login(WebDriver driver,String username,String password){ LoginPage.login_UserName(driver).sendKeys(username); LoginPage.login_Password(driver).sendKeys(password); LoginPage.login_Button(driver).click(); } public static void main(String[] args) throws InterruptedException { driver = new ChromeDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get("http://www.126.com"); Login(driver,"username","123456"); Thread.sleep(5000); driver.quit(); System.out.println("test case run end!"); } }
定义 login()方法的好处就是再创建测试用例的时只关心测试数据(用户名和密码),而不用考虑“登录”到底需要几个步骤。
一个有分歧的地方是 page 对象是否应自身包含断言,或者仅仅提供数据给测试脚本来设置断言。在page 对象中包含断言的倡导者认为,这有助于避免在测试脚本中出现重复的断言,可以更容易地提供更好的错误信息,并且提供更接近只做不问风格的 API。不在 page 对象中包含断言的倡导者则认为,包含断言会混合访问页面数据和实现断言逻辑的职责,并且导致 page 对象过于臃肿。我赞成在 page 对象中不包含断言,虽然我们可以通过为常用的断言提供断言库的方式来消除重复,这可以提供更好的诊断,但从站在用户的角度去自动化的观点来看,判断是否登录成功是用户需要做的事情,不应该交给页面对象层来完成。
使用 Page Object 模式之后的另外一个好处就是有助于降低冗余。如果需要在 10 个用例里面都输入不同用户名密码登录,那么用 main()方法写起来将会变得非常简便。因此,Page Object 模型的作用在一个测试人员自己写主场景测试案例时是不容易体会到的,因为你不需要和开发、业务交流案例,也不会写很多重复动作。但是,当你真正开始尝试 ATDD 或 BDD,当你开始写一些重要的异常分支流程时,当你开始为新需求频繁维护修改案例时,就会意识到 Page Object 的作用。