关于PO设计模式的介绍

POM概述

Page Object Model (POM) 是一种设计模式,通常用于自动化测试中,主要思想是通过分层的方式将对象、操作、业务分开处理以减少和业务逻辑或判断的耦合度,从而提高测试用例的可维护性

Martin Fowler 提出编写测试用例的POM的设计模式,后续在selenium等自动化测试框架中都得到很好的应用

为什么选择POM

如当你对web页面进行自动化测试时,你需要操作该web页面上的元素来点击链接或验证显示的内容。你可以在测试代码中直接操作html元素,进行一连串的操作后进结果进行断言验证。但当页面UI发生变化时,你的测试代码将变得极其脆弱。而且当测试用例多起来过后,这样的测试用例将变得不可维护。

这时候我们就需要采用POM,一个page对象(一个类对象)可以封装一个html页面或部分页面(这里的page不一定是一个完整的页面,也可以是该页面的一个特定模块,可以根据自己的业务需求来进行封装),在每个page中通过提供特定的API(特定的函数/方法)来操作页面元素(把元素信息和操作细节封装到page类中),而不需要在测试用例中来对html元素进行操作。

以后当html元素发生变化时,只需要修改page 类文件中的特定方法中的元素操作,而不需要修改所有的测试用例。这有助于使代码更具可读性、可维护性和可复用性。

POM的优点

  • 可维护性
  • 可复用性
  • 可读性和可靠性

怎么实现POM

如以下测试用例:打开登录页面--> 输入用户名密码-->点击登录-->跳转主页-->验证主页面包含用户id
在这我们就可以封装两个page:LoginPage(登录页),HomePage(主页)
伪代码如下:

  • LoginPage
username = By.name("uid");
password = By.name("password");
login = By.name("btnLogin");

setUserName(strUserName) {
    driver.findElement(username).sendKeys(strUserName);
}

setPassword(strPassword) {
    driver.findElement(password).sendKeys(strPassword);
}

clickLogin() {
    driver.findElement(login).click();
}

login(strUserName, strPassword) {
    setUserName(strUserName);
    setPassword(strPasword);
    clickLogin();
}
  • HomePage
homePageUserName = By.xpath("//table//tr[@class='heading3']");
getHomePageUserName() {
    return  driver.findElement(homePageUserName).getText();
}
  • testcase
setup();
test_Login { 
    LoginPage.login("monkeyjerry", "123!123");
    Assert.assertTrue(HomePage.getHomePageUserName().toLowerCase().contains("manger id : monkey"));
}

POM编写的六大原则

  • The public methods represent the services that the page offers
  • Try not to expose the internals of the page
  • Generally don't make assertions
  • Methods return other PageObjects
  • Need not represent an entire page
  • Different results for the same action are modelled as different methods

翻译及理解:

  1. 公共方法代表页面提供的服务。比如点击页面中的元素跳到到新的页面,于是就可以为这个服务封装方法:“进入新页面”
  2. 不要暴露页面内部细节。只对外提供方法(接口)
  3. 不要在页面中使用断言。在页面中的操作中不要使用断言,断言放在测试用例中
  4. 方法可以return到新打开的页面。点击一个按钮跳转到新的页面,这个页面如登录成功页面,则可return到新的po如PersonalCenterPage
  5. 不要把页面整个内容放在page中。只为页面重要的元素进行po设计
  6. 相同的行为可产生不同的结果,可以封装成不同的方法。如登录操作,可以封装login_success(), login_error()两个方法

编写规则扩展

  • 总体规则
    所有模块设计均遵循 page object 结构
  1. 用例层:测试人员编写测试用例代码的地方,可以调用 page 层和封装层
  2. page 层:一个页面一个类,包含该页面的业务逻辑封装以及部分控件定义
  3. 封装层:根据业务需要,封装常用的业务逻辑 (相比于 page 层的业务逻辑封装,它的范围更广,有些时候是跨页面的业务逻辑。 属于模块级的业务封装)
  • 页面设计规则
  1. 所有导航,页面辅助以及会跨越多个页面的逻辑均设计为接口,接口中定义默认实现
  2. 每个 page 类只负责自己页面的逻辑
  3. 页面类的类名以 Page 为结尾。 接口 (共用逻辑) 不得使用 Page 结尾
  4. 每个页面以封装业务逻辑为主,通过参数控制调用不同的业务逻辑。 无特殊情况下不要让外界知道控件的信息
  5. 所有页面逻辑皆返回特定页面对象,以保证测试用例使用 workflow 式 API
  • 用例编写规则
  1. 每个 case 都必须使用 Features,Stroies, Title 标注来为 case 添加 report 信息 (我们使用的是 allure 这个 report 框架), 根据情况可以添加 Description 标注
  2. case 中涉及 UI 上创建的实体名称,比如项目,数据,模型,用户等都需要使用随机名称。 不能使用固定名称。 以防一个环境多次运行的时候因为名称冲突而失败
  3. case 中不准许出现页面元素信息,所有页面元素的封装和业务逻辑的封装要写在 page 层中

参考及扩展阅读