UI层自动化测试框架(四):对象库层
引言
本章主要介绍自动化测试框架–对象库层。该层是UI自动化中比较关键的一层,设计自动化框架,不可避免的就是对象库,有一个好的对象库,可以让整个测试框架可维护性更高,大大增强了代码的复用性。
讲之前先和大家普及个一概念:PO模式
PO模式
那什么叫PO模式,为什么要用PO模式?引用如下一段话,你就会恍然大悟~
PO模式,全称Page Object模式,是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,其中包含页面中需要测试的元素(按钮,输入框,标题 等),这样在写测试脚本时,可以通过调用页面类来获取页面元素。当页面某个元素id或者位置变化时,这时不用更改测试脚本,只用改下对应的页面类就行了。
上面这段话,总结一下就是:PO就是一个设计模式,将代码以页面为单位进行组织,针对这个页面上的所有信息,相关操作都放到一个类中;从而使具体的测试用例变成了简单的调用和验证操作。
如果你深刻理解了就应该知道了PO对象的好处,当然这只是阐述啦它的可维护性,但它的复用性就更好理解,这里就不多做解释。
对象库的引入
对于上面讲的PO模式,大家会不会有一个疑惑?这样一来一个app有很多page,以DJI GO为例50个左右肯定是有的吧,那这样是不是要设计50个页面类,然后每个页面类中写对应的元素。这样一来单单页面类就写这么多,感觉工程量太大,而且代码的复用性不高。
那有没有什么改进的办法呢?
1.首先定义一个BasePage类,毕竟所有的页面都有共同的东西,每个页面都有元素,每个页面元素都有相应的方法。该类包括一个成员变量 pageName,和封装的的方法。重写它的构造方法,用来初始化成员变量。以后每次调用某个页面时,只用new一个BasePage对象,传入对应的参数pageName,就获得对应页面。
package com.dji.object;import java.io.IOException;
import java.util.HashMap;import com.dji.utils.AppiumExecutorImpl;
import com.dji.utils.Log;
import com.dji.utils.XmlUtils;import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;/*** 封装一个BasePage的类,毕竟所有的页面都有共同的东西,每个页面都有元素,每个页面元素都有相应的方法* * @author Charlie.chen**/public class BasePage extends AppiumExecutorImpl {protected AppiumDriver<?> driver;protected String pageName; //页面名称protected String xmlPath; //页面元素路径protected HashMap<String, Locator> locatorMap;public Log log = new Log(this.getClass());public BasePage(AppiumDriver<?> driver,String pageName) throws Exception {super(driver);this.driver = driver;this.pageName=pageName;//获取资源文件page.xml的路径//xmlPath=System.getProperty("user.dir")+"\\src\\main\\java\\com\\dji\\pageObject\\Page.xml"; xmlPath=BasePage.class.getClassLoader().getResource("page.xml").getPath();//locatorMap = XmlUtils.readXMLDocument(xmlPath, this.getClass().getSimpleName());locatorMap = XmlUtils.readXMLDocument(xmlPath, pageName);}public void type(String locatorName, String values) {super.type(getLocator(locatorName), values);log.info("type value is: " + values);}public void click(String locatorName) {super.click(getLocator(locatorName));log.info("click: "+locatorName);}public String getText(String locatorName) {// TODO Auto-generated method stubreturn super.getText(getLocator(locatorName));}public MobileElement findElement(String locatorName) {// TODO Auto-generated method stubreturn super.findElement(getLocator(locatorName));}public boolean isElementDisplayed(String locatorName) {// TODO Auto-generated method stubreturn super.isElementDisplayed(getLocator(locatorName));}/*** 根据locatorName获取Locator* * @author Charlie.chen* @param locatorName* @return* @throws IOException*/public Locator getLocator(String locatorName) {Locator locator = null;if(locatorMap!=null){locator = locatorMap.get(locatorName);}return locator;}}
上述代码中有个一个集合locatorMap,主要存储的对应的pageName和Locator内容
2.接下来封装元素,每个元素都有相应的定位地址(xpath路径或css或id),等待时间,定位方式
package com.dji.object;/*** 封装页面元素,每个元素都有相应的定位地址(xpath路径或css或id),等待时间,定位方式* * @author Charlie.chen**/public class Locator {private String address; //定位地址private int waitSec; //等待时间private ByType byType; //定位方式/*** 定位类型枚举* @author Charlie.chen**/public enum ByType{by, xpath, linkText, id, name, className}public Locator() {}/*** Locator构造器,默认定位类型By.xpath* * @author Charlie.chen* @param element*/public Locator(String address) {this.address = address;this.waitSec = 3;this.byType = ByType.xpath;}public Locator(String address, int waitSec) {this.waitSec = waitSec;this.address = address;this.byType = ByType.xpath;}public Locator(String address, int waitSec, ByType byType) {this.waitSec = waitSec;this.address = address;this.byType = byType;}public String getAddress() {return address;}public int getWaitSec() {return waitSec;}public ByType getBy() {return byType;}public void setBy(ByType byType) {this.byType = byType;}public ByType getByType() {return byType;}}
对象库的管理
针对上面的两个类BasePage和Locator,其实就是分别代表页面对象库和元素对象库。关于对象库的管理,就是将对象库中的数据,类似pageName和元素属性id,xpth等分离出来保存在page.xml文件中,这样做到了数据隔离的效果,维护性更高。
page.xml如下
<?xml version="1.0" encoding="UTF-8"?><map><!--locator of page map info --><page pageName="menuPage"><!--Locator lists --><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'设备')]">设备</locator><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'编辑器')]">编辑器</locator><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'天空之城')]">天空之城</locator><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'我')]">我</locator></page <page pageName="minePage"><!--Locator lists --><locator type="id" timeOut="3" value="dji.pilot:id/icon_user">用户图像</locator><locator type="id" timeOut="3" value="dji.pilot:id/mine_user_name">用户名</locator><locator type="id" timeOut="3" value="dji.pilot:id/v2_mine_store">DJI商城</locator><locator type="id" timeOut="3" value="dji.pilot:id/v2_mine_academy">DJI论坛</locator><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'礼品卡')]">礼品卡</locator><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'上传队列')]">上传列表</locator><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'消息')]">消息</locator><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'我的收藏')]">我的收藏</locator><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'更多')]">更多</locator><locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'设置')]">设置</locator> </page><page pageName="loginPage"><!--Locator lists --><locator type="id" timeOut="3" value="dji.pilot:id/edt_email">登录输入账号框</locator><locator type="id" timeOut="3" value="dji.pilot:id/edt_password">登录输入密码框</locator><locator type="id" timeOut="3" value="dji.pilot:id/btn_sign_ok">登录</locator></page><page pageName="settingPage"><!--Locator lists --><locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_back_button">返回</locator><locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_cellular_switch">使用手机流量上传文件</locator><locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_develop_switch">开启USB调试</locator><locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_reset_guide_button">重置新手指引</locator><locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_clean_cache_button">清除数据缓存</locator> <locator type="id" timeOut="3" value="dji.pilot:id/mine_language_change">多语言</locator><locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_privacy_button">隐私设置</locator><locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_rate_app_button">给我们评分</locator> <locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_sign_out_button">退出DJI账号</locator><locator type="id" timeOut="3" value="android:id/button2">取消</locator><locator type="id" timeOut="3" value="android:id/button1">确定</locator><locator type="id" timeOut="3" value="dji.pilot:id/mine_user_protocol">DJIGO用户协议</locator> </page></map>
分析一下page.xml中登录页,对应的pageName=“loginPage”,对应的元素名有“登录输入账号框”,“登录输入密码框”,“登录按钮”和对应的定位方式和等待时间。这样是不是一目了然,以后如果页面元素属性发生变化,只用改下以上配置文件即可。关于xml文件的读取,在第三章中有讲过,通过XmlUtils进行读取,将读取的信息保存在HashMap集合locatorMap中。
总结
总结一句话:就是将页面和元素封装在两个类中,然后将对应的数据抽离出来放在xml文件中管理。
对象库大大提高了测试框架的复用性和可维护性,在测试框架中起到核心作用,这里只是我的处理方式,相信还有更简洁更易度的方法,等待大家去挖掘。
下一章主要讲解 自动化测试框架(五):业务层和用例层,敬请期待!!
UI层自动化测试框架(四):对象库层相关推荐
- UI层自动化测试框架(一)-简介和环境搭建
大家好,本系列教程主要介绍基于Appium的UI层的自动化测试框架的设计和实践.我将平时的学习和工作的实践一一的总结下来,给初学者一点灵感和启发,如有不对的地方还请大家指出. 所谓UI层自动化,顾名思 ...
- ArcGIS Engine开发:框架/结构+对象库
ArcGIS Engine开发:框架/结构+对象库 框架/结构: ArcGIS Engine 开发人员有权使用一系列的控制器,这些控制器 准许很多属性.事件和方法的使用.尽管一个简单的应用软件 仅仅通 ...
- UI层自动化测试框架(三):基础层
引言 第一章我就有说到,该自动化测试框架分为四层:基础层,对象层,操作层,用例层.本章主要介绍基础层的设计. 测试框架目录如图: 对应源码地址:https://github.com/iTestingl ...
- java domain层_java框架中的controller层、dao层、domain层、service层、view层
1.Controller层:接口层,用户访问请求时对接. Controller层负责具体的业务模块流程的控制,在此层里面要调用Serice层的接口来控制业务流程,控制的配置也同样是在Spring的配置 ...
- UI层自动化测试框架(五):业务层和用例层
业务层 该层主要是App的各种业务操作,比如登录,遍历tab,下单等,也就是说把app中各项业务的操作都封装在业务层.比如说登录操作,我们把它封装一个类,登录的大致的流程是:首先是不是要找到登录入口( ...
- UI层自动化测试介绍
UI指的是用户可以用肉眼可以看到的页面. UI层自动化测试的原理.不论是web端还是移动端,原理都是一样的,就是基于页面元素的识别和定位来进行模拟用户行为. 首先识别到某个元素,比如一个按钮,然后定义 ...
- UI 自动化测试框架:PO 模式+数据驱动
1. PO 设计模式简介 什么是 PO 模式? PO(PageObject)设计模式将某个页面的所有元素对象定位和对元素对象的操作封装成一个 Page 类,并以页面为单位来写测试用例,实现页面对象和测 ...
- (转载)UI接口分层自动化测试框架设计思想
阅读本小节,需要读者具备如下前提条件: 1. 掌握一种编程语言基础,如java.python等. 2. 掌握一种单元测试框架,如java语言的testng框架.python的unittest框架. ...
- 学习笔记——自动化测试框架的构成
自动化测试框架的构成 一.基础模块 1.底层核心驱动 2.可复用组件 3.对象库 4.配置文件 二.管理模块 1.测试数据管理 2.测试文件管理 三.运行模块 四.统计模块 常用的测试框架 1.模块化 ...
最新文章
- JavaScript学习笔记(四十四) 装饰器
- 网页中二维码识别规则
- 判断 iframe 是否加载完成的完美方法(转)
- 千寻的计算机字符,转义字符变量与赋值
- Eclipse提速优化方法
- geany配置python3.8_Parrot security 4.10-amd64
- Python:pathlib库使用方法
- mtl库在GCC编译器下的使用
- 【Ansible 文档】【译文】Ad-Hoc 命令介绍
- 【缓存】J2Cache —— 基于内存和 Redis 的两级 Java 缓存框架的使用方法
- recv函数linux,linux 下调用recv函数,死循环在recv函数里面,什么原因?
- 易优CMS:arcpagelist 瀑布流分页列表
- python给全局变量赋值_Python 进程之间共享数据(全局变量)的方法 python 全局变量赋值的问题...
- Qt线程、事件与QObject
- 漫谈Commons-Collections反序列化
- Bonobo.Git.Server 401 Error
- 基于STM32F103单片机的智能药盒喂食器智能插座系统
- 云卷云舒、淡定人生,学会独处!
- Arduino通信协议设计
- Bently Nevada本特利9200速度传感器简介 及选型注意事项
热门文章
- 推荐5个堪称神器的学习网站,在家你值得拥有
- 什么是Mybatis?Mybatis能干什么?Mybatis怎么配置?
- 新架构、新场景、新范式之下 数字化转型的“懂行”驱动力
- 利用HFS软件一分钟搭建好ESP8266基于Arduino开发环境
- 新造车,程序员的糖,工程师的泪
- 网页视频播放php拉伸代码,网页在线播放mp4/flv等格式视频方法,CuPlayer(酷播)详细使用方法(附源代码)...
- 钉钉企业内部机器人python开发(公网部署版本)
- c++中的指数函数怎么写
- ViewBinding和DataBinding的区别
- Linux rpm -ivm,PowerLinux 7R1项目实施手册PDF