Selenium之Page Object模式
Selenium之Page Object模式
Page Object Model(POM)方案发展史
- 2013 Martin Flower:https://martinfowler.com/bliki/PageObject.html
- 2015 Selenium:https://github.com/SeleniumHQ/selenium/wiki/PageObjects
- Selenium Python Client:https://selenium-python.readthedocs.io/page-objects.html
- Mozilla PyPOM:https://pypom.readthedocs.io/en/latest/
PageObject模式
- 做法
- 以页面未单位独立建模
- 隐藏实现细节
- 本质面向接口编程
- 优点
- 减少重复find click样板代码
- 易读性提高
- 页面修改不影响测试用例
Image From Martin Fowler
Selenium 正式引入
2015年3月,selenium正式引入PageObjects模式
Page Object Model的基本原则
Summary
- 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
PageObject模式原则解读
- 方式意义
- 用公共方法代表UI所提供的功能
- 方法应该返回其他的PageObject或者返回用于断言的数据
- 同样的行为不同的结果可以建模为不同的方法
- 不要在方法内加断言
- 字段意义
- 不要暴露页面内部的元素给外部
- 不需要建模UI内的所有元素
场景示例说明:登陆场景
- 登陆页面提供login findPassword功能
- Login类+login findPassword方法
- 登录页面内的元素有多少并不关心,隐藏内部界面控件
- 登录成功和失败会分别返回不同的页面
- findPassword
- loginSuccess
- loginFail
- 通过方法返回值判断登录是否符合预期
Java Python的封装方法
- java: page factory + @FindBy
- python: pythom https://github.com/mozilla/PyPOM/
各个语言的binding都实现了po的简单封装,但是使用效果不好,需要自己定制
基于POM的用例组织结构
- page:完成对页面的封装
- testcase:调用各类page完成业务流程并进行短验
- data:配置文件和数据驱动
- utils:其他便捷的功能封装
编写用例顺序
- 根据界面封装PO类方法,实现暂时设置为空
- 编写用例,明确po里方法的入参、返回值、断言
- 实现po内的方法,与自动化框架开始结合
- 调试
- 整体类似TDD风格
原生Selenium PO模式
框架默认PO定位策略的不足
- UI的控件定位有复杂性,需要自定义
- 动态加载的UI,可以找到但是位置可能发生变动
- 动态加载的空间可能会获取到最早的默认值
- 动态出现一些tips需要特殊处理
- 改进(修改较为麻烦,需要对底层深入理解)
- 自定义find方法,更灵活的find行为定义封装
- 改进默认的注解
不推荐使用原生PO支持
- 真是的情况更复杂,原生PO支持方法不足以应对
- 不容易定制,比如Java注解,维护注解需要较高的成本
- 多数公司都在使用相同的Page Object思想进行自定义封装
实战说明
企业微信web版进行自动化案例演示
企业微信地址:https://work.weixin.qq.com/wework_admin/frame
注意:企业微信登录需要扫二维码登录
Cookie登录
登录企业微信后,获取Cookie(获取Cookie的方式在另一篇文章介绍,具体可看该文章),由于扫二维码必须由人工介入,登录只能是Cookie的方式
处理获取的Cookie,处理成Driver需要的格式
复制第一步获取到的cookie,使用awk处理成我们想要的格式(awk方式只是之一,也可以使用其他的方式)
编写测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40package com.auto.demo.web;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.chrome.ChromeDriver;
/**
* @author jingLv
* @date 2020/11/30
*/
public class TestWeWork {
void openChrome(){
String url = "https://work.weixin.qq.com/wework_admin/frame";
ChromeDriver driver = new ChromeDriver();
driver.get(url);
driver.manage().addCookie(new Cookie("pgv_pvid", "965326920"));
driver.manage().addCookie(new Cookie("wwrtx.c_gdpr", "0"));
driver.manage().addCookie(new Cookie("pac_uid", "0_aee823a5acb34"));
driver.manage().addCookie(new Cookie("wwrtx.i18n_lan", "zh"));
driver.manage().addCookie(new Cookie("_ga", "GA1.2.486968943.1606468059"));
driver.manage().addCookie(new Cookie("wwrtx.ref", "direct"));
driver.manage().addCookie(new Cookie("wwrtx.refid", "4250759204197565"));
driver.manage().addCookie(new Cookie("wwrtx.ltype", "1"));
driver.manage().addCookie(new Cookie("wxpay.corpid", "1970324947149288"));
driver.manage().addCookie(new Cookie("wxpay.vid", "1688850129600022"));
driver.manage().addCookie(new Cookie("wwrtx.vid", "1688850129600022"));
driver.manage().addCookie(new Cookie("ww_rtkey", "1166bq8"));
driver.manage().addCookie(new Cookie("Hm_lvt_9364e629af24cb52acc78b43e8c9f77d", "1606468059,1606468075,1606469576,1606714819"));
driver.manage().addCookie(new Cookie("Hm_lpvt_9364e629af24cb52acc78b43e8c9f77d", "1606714819"));
driver.manage().addCookie(new Cookie("_gid", "GA1.2.1004022239.1606714820"));
driver.manage().addCookie(new Cookie("wwrtx.d2st", "a532885"));
driver.manage().addCookie(new Cookie("wwrtx.sid", "6QnZz9M3D9-XwaqXVRhlplYnrydnCorqqH61w8jMbhRbcTni27ASNi5GwQRoRc5t"));
driver.manage().addCookie(new Cookie("wwrtx.vst", "ls7NqhOyvl2ER2hxI3QOsG8TBvjH-uVP7U8ymdRREjZQ5t5Nagz1nbTVjEPlAmowyB1hK90UquW63nmuOgtSNryFZYa916K9L8enRAa-RMt73xWiFHBYjCToPxoNsUD38YMpiVYPLsLdTrlR0oIuBSZmznOonOYr8i7W5KoCVfyeV6QK0QesguC5GqNjDGq9btyGaDpKJr18dE_j-Hl0FrVmGMig4VJhv_UKNHEYKQtTEsu3uFCfTquGCh1VUZZQfxs2w_aLM4_5flndp7EVEg"));
driver.get(url);
}
}
业务流程案例
实现企业微信的登录后,可进行以下的流程的测试:
- 通讯录增加成员
- 通讯录搜索成员
- 通讯录删除成员
根据以上需求,以PO的思想模式,进行通讯录页面的封装(演示简单的流程操作)
1 | package com.auto.demo.web.page; |
注意:元素等待的问题,使用了显示等待后,依旧会有部分元素不可操作,因此为了增加稳定性,使用了循环进行控制,该循环是死循环因此又出现了问题,当元素真的不存在时,死循环就会不停的查找操作,会导致流程陷入该步骤的死循环中,不会后续的步骤进行,后续会继续优化
现在简单的封装了”通讯录“的页面,但是访问”通讯录“的提前是需要进登陆操作的,因此在这个基础上简单封装一个主页面进行Cookie登录和WebDriver的声明
1 | package com.auto.demo.web.page; |
测试代码
1 | package com.auto.demo.web.testcase; |
代码示例github地址:https://github.com/jinglv/selenium-for-java
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Jing's Blog!