以下文章转载自我的云栖社区:UI 自动化 Macaca-Java 版实践心得
在上篇分享中,跟大家分享了Macaca-Java 版入门指南,相信很多同学已经可以依据教程开始实践 UI 自动化工作,但入门问题解决了,要真正在业务中实践还需要面临不少挑战,这篇文章则紧接上一篇,就 Macaca 在业务中的实际应用给出一些经验总结,希望能给在迷茫中不知如何入手的同学们一些方向,同时欢迎大家就本篇文章中涉及的一些方案给出更优的答案,大家一起进步。
首先,我们看一下对于单个平台,是如何做控件的查找与操作的:
//SampleTest.java
public void test() throws Exception {
driver.elementById("targetElementId"); // elment的唯一标识
driver.click();
}
当平台扩展为多个时,一般来讲,如何进行同一个控件的操作呢?比如对应同一个按钮,在 iOS 平台,我们可以知道他的 name 属性,但是在安卓平台,对应的同一个控件,没有 name 属性,需要通过 id 属性来获取,那代码就会演变成如下样式:
//SampleTest.java
public void test() throws Exception {
if (driver.curPlatform==PlatformType.IOS)
{
// 如果是iOS平台,根据name属性查找控件
driver.elementByName("targetElementName");
driver.click();
} else {
// 如果是安卓平台,根据id属性查找控件
driver.elementById("targetElementId");
driver.click();
}
}
众所周知,对于 UI 自动化,控件的查找是使用相当频繁的一种操作,那么问题来了,有没有一种方式,可以统一控件的查找而不必通过一个接一个的 if else 分支来完成呢?
测试的稳定性,是影响自动化测试的另一大因素,因为移动端操作场景的复杂性,测试用例执行的过程中可能出现多种意料之外的响应,比如点击某一个按钮,预期结果是进入下一个页面,但是却弹出了某个弹框,或者真正跳转的页面并不是我们所预期的页面,或者跳转了我们所预期的页面,但因为网络数据的加载主视图并没有刷新,这样一来,针对我们的目标页面所做的操作都会失败,因为我们无法找到预期页面的目标控件,在这种情况下,我们需要在保证预期页面已经加载的情况下再执行预期流程的用例,如何做到这一点呢?
再者,长距离到达组件入口的问题也是影响自动化稳定性的另一因素,比如我们想要测试某个基金详情页,但是要进入某个详情页,必须经过登录 - 首页-A 页面-B 页面 - 目标页面几个必须步骤,在到达目标页面之前的任何一个链条中出现中断,这次测试就等于无效了,这种问题怎么破?
当然,影响自动化测试稳定性的场景还有很多,这些在真正的业务实践中会逐步暴露出来,如何保证自动化测试的稳定性,是自动化测试的又一个难题。
对应每一项测试流程,执行完毕之后我们都希望能看到详尽的测试报告,如何快速高效的输出可读性强的测试报告,同样是一个必须解决的问题。
自动化平台或者工具如果对环境配置、使用规范,脚本等有较复杂要求的话,那么对于入门刚刚的测试工程师来说有一定的学习成本。另外,跟随目标产品的版本迭代,自动化脚本要做对应的调整,如果对应的调整成本比较高,也很难保证将自动化的工作方式坚持下去。
研究上面的第一个问题,我们会发现控件的获取虽然根据平台不同而需要单独处理,但是控件的获取方式其实都是统一的,获取控件有两大要素,一是获取控件的方式,比如 name,id,xpath,css,class name 等等,二是要获取控件的值,这个值是与获取控件的方式想对应的,针对移动端测试来说,目前一般覆盖 iOS,Android 两个平台,我们以这个为例,其实对于 UI 操作上的一个控件,提供两个平台分别的获取方式以及值就可以解决控件一致性的问题,代码如下:
// CommonUIBean.java
/**
* 当安卓 ios两个平台对应同一控件的获取方式不一致时使用本构造函数
* @param androidBy 获取安卓对应控件的方式
* @param androidValue 获取安卓对应控件的值
* @param iosBy 获取ios对应控件的方式
* @param iosValue 获取ios对应控件的值
*/
public CommonUIBean(GetElementWay androidBy,String androidValue,GetElementWay iosBy,String iosValue){
this.androidBy = androidBy;
this.androidValue = androidValue;
this.iosBy = iosBy;
this.iosValue = iosValue;
}
/**
* 构造函数,用于ios&android两个平台获取UI一致的情况
* @param commonBy 统一获取控件方式
* @param commonValue 统一获取控件值
*/
public CommonUIBean(GetElementWay commonBy,String commonValue){
this.androidBy = commonBy;
this.androidValue = commonValue;
this.iosBy = commonBy;
this.iosValue = commonValue;
}
如上图这样,我们就统一了控件的一次性获取问题,通过这一层封装,如果要表示跨两个平台的一个控件,就可以简化为如下这样:
CommonUIBean targetElement = new CommonUIBean(GetElementWay.ID,"targetElementId",GetElementWay.NAME,"targetElementName");
1、对于要测试的页面抽象成类,增加页面是否加载成功的逻辑,所有页面内部的测试逻辑,均在确认该页面加载成功后再执行从而保证自动化稳定性。
2.对于长距离到达组件入口的问题,通过 scheme 跳转解决。具体来讲,对于目标页面,只要支持 scheme 跳转,我们可以直接通过 scheme 的方式从首页直接进行加载,这样可以一步到达目标页面,省略掉了前面的诸多链路,从而保证了测试的稳定性。当然,这种方式需要依赖开发同学的支持,只有在开发层面上尽可能多的支持独立页面的 scheme 跳转方式,才能真正使这个解决方案大放光彩。
当然,除了这些之外,对于其他分支的阻塞场景,一方面需要我们对业务复杂度的深入了解,一方面需要在今后的实践中不断积累。
对于这个问题,我们是分这么几步走的:
1.按照业务需求将错误类型进行分类整理
2.规范化结果输出的规则
3.在对应节点按照既定规则输出日志并写入文件
这样,用例执行结束后,我们就可以看到具体的执行过程以及结果了,规范化日志输出的规则还有一个好处是便于今后结果的集成展示,比如我们要通过 web 直观的看到执行进度以及结果的时候,就可以通过解析日志得到相应数据。
关于学习成本,就要回到我们的标题,我们这里讲的是 Macaca-Java 版最佳实践,其实在最早的调研阶段,我们都是通过 Javascript 写用例的,但是考虑到大部分同学的学习成本,所以在 Macaca 支持 Java 后,我们立即转型到 Java 版本上来,这样大大减小了学习成本,另外,我们在设计自己的框架的时候,设置了 config 配置文件来配置通用信息,比如应用信息、用户信息等都可以通过配置文件配置,对于用例编写中常用的类进行了封装,形成了一套用例编写规范,这些对于新上手的同学都降低了接入成本,甚至对于不熟悉 Java 的同学,都可以比较 easy 的比葫芦画瓢的编写自己的用例。
关于维护成本,我们对于控件的封装使控件更新的成本变低,对于 Page 的封装,使得同一个页面的测试入口都集中在一起,每个页面各自维护自己的操作入口,这样当我们需要测试一个流程时,只需要把经过的页面对应的操作组装到一起就可以了,当我们需要更新某一个页面的某个操作时,只需要去页面对应的类中去修改指定的操作,而不影响原有的流程化逻辑,具体请参考源码。
广告时间结束,正片从这里开始。
上面讲了这么多内容做铺垫,相信很多同学已经不耐烦的想要直接看源码了,好的,这就满足泥萌。不过要成功的跑起我们的测试用例来,必须保证本机已经配置好了 Macaca 的相关环境,还没配置的同学请参考我上一篇文章Macaca-Java 版入门指南
目前我们已经将如上介绍的应用层部分源码封装成为独立的 biz 层以 Jar 包的形式提供,同时提供了一个接入 biz 层的 sample,对应的源码均已开源,地址如下:
下面我们以 sample 为例,讲解接入以及使用方法:
$ git clone https://github.com/macaca-sample/macaca-java-biz-sample.git
$ cd macaca-java-biz-sample
$ make install
如果下载依赖过程中报错,可能是由于 mvn -s 命令没有生效导致的,建议将根目录下 settings.xml 中的依赖配置到本地 Maven 目录下的 settings.xml 中。
// Config.java
// 目标平台- ios android
public static final String PLATFORM = "ios";
注意:执行 iOS 用例时需要将 XCode 升级到最新的 8.1,执行用例前请先启动目标模拟器。
$ macaca server --verbose
注意启动 server 时不能加代理,因为 server 在本机启动需要连接 localhost,加代理会导致无法建立连接。
$ mvn -s settings.xml test
如果你成功跑起来了用例,那么下一步我们就来详细研究一下 Demo 的源码部分了,如果你非常不幸的因为各种原因没能 run 起来,请先保证 Macaca 的环境已经正常安装 (macaca-doctor),如果环境正常但还是启动失败,请毫不吝啬的联系我。
下面给出一张各 package 的作用讲解,在看过这部分之后相信大部分人已经基本清楚这个框架的基础结构了,然后更深入的理解,还需要大家认真去研究一下源码。
目前的框架已经解决了一些自动化测试用例编写中的基本问题,但是在写过一定量的 case 后,我们会发现 case 的组装实际上是一种类似的逻辑:获取控件 (通过多种方式) -> 对控件进行某种操作 (click)->与预期结果进行对比得到 case 执行结果,这有限的几种,既然这些操作如此相似,那我们是不是可以通过一种数据驱动的方式更有效的进行 case 的管理,就像如下这张图这样:
最后我们期望达到的效果是建立一个管理系统,将所有的流程通过用例管理系统进行如上信息的管理,最终实现零编码的自动化用例设计,当然这其中还需要解决诸多问题,需要我们在积累编写经验的同时不断完善。也欢迎志同道合的同学们加入到这个过程中一起努力!
想象一下我们的自动化测试工作已经正常投产,然后在运行过程中我们发现了一些 bug,这时候开发就需要去解决这些 bug,对于开发同学,我们现在能提供的是 bug 出现时的屏幕截图,但是很多时候仅仅依赖一个截图是不能帮助开发同学去定位真正的问题的,如果能获取用户当时的请求和后端的返回数据,结合屏幕截图,则能大大的方便开发同学定位并解决问题,这一步要如何实现,还需要我们进一步的思考。如果这一步完成了,那么我们相当于将线上巡检与 UI 自动化结合在了一起,无疑是一件很有意义的大跨越。
除了网络数据,还有很多可以和 UI 自动化结合的点子,比如埋点,比如监控,因为 UI 操作是一切 app 行为的基础,所以从 UI 自动化出发,我们有很多事情可以做,有没有热血沸腾了呢?
“Macaca 开源社区” 群的钉钉群号: 11775486(欢迎入群讨论,钉钉顶部搜索框搜索群号加入即可)
UI 自动化框架调研总结
从无到有搭建 Macaca 环境 (forMac)
Macaca-Java 版入门指南
UI 自动化 Macaca-Java 版实践心得
UI 自动化利器 - 为你的应用自动添加控件 ID 探索
Macaca 基础原理浅析