自动化测试可行性分析
针对android-nova
项目,每个新版本发布之前,RD 都需要进行主流程回归,这是一项重复且耗时的工作,“重复”是指每2~3周发版时就要进行一次,“耗时”则因为平均一条业务线要用一个小时时间——这还只是单android平台。
实现自动化后,可以大大减轻 RD 负担,并且可在迭代过程中建立 daily build 机制,及早发现问题,提高提测质量。
对自动化测试的理解
这里只针对 UI 方面的白盒测试
- 自动化测试的输入是用户操作(输入、点击、滑动)、网络请求返回
- 自动化测试的输出是 UI 控件显示
这两步都可以通过现有的自动化工具完成
自动化工具选取
之前组内分享了2个自动化工具,Robutium 和 Appium。查阅相关资料后,发现网络上比较流行的不外乎也就是这两个。简单罗列出各自的特点:
Robotium | Appium | |
---|---|---|
是否开源 | 是 | 是 |
测试类型 | 黑盒 | 黑盒 |
支持平台 | Android | Android, iOS, FirefoxOS |
apk是否需要再编译 | 需要,测试代码必须打入apk包 | 无需,测试代码单独存放 |
可测App类型 | 原生,hybrid | 原生,hybrid,甚至可以通过Safari/Chrome来测试web页面 |
安全性 | “The most notable limitation”, 操作仅限本 app | 未知 |
用例语言 | Java | Any WebDriver-compatible language: Java, Python, PHP, C#, OC… |
参考资料 | Android Robotium自动化测试使用手册 by 楼赟程 | Android Appium自动化测试指导手册 by 覃少强 |
比较之后,选用Appium作为实践手段
难点
如果要实现自动化测试,总结下来,以下几个方面是难点,也是必须解决的问题
- 预设数据保存、读取
- 预设数据填入组件
- 模拟请求发送接收
- 检验接收后的界面展示
其中2
&4
可以由测试框架帮助完成,1
&3
比较棘手,详见本文讲述。
Appium配置与运行
历时一天才跑通了Appium的demo,不得不再次感慨,中文博客的帮助的确是太太太太少了。首先要确认平台是OS X,其次还要是为android进行测试,好不容易找到了一些,发现大家都是一模一样的,不知道是谁抄谁。关键是你抄来抄去,抄的净是些错误内容……
自己途中遇到一些曲折,记录如下
- 理解Appium所使用的
client-server-app
的结构,client
的代码不应该写在app
里
我是这么处理的:- client:maven项目,用IntelliJ编写,测试代码位于
test/java/com.leili.demo.Demo
,注意maven项目要在pom里处理好依赖(见代码) - server:Appium的GUI界面,完成配置即可使用,不需二次开发
- app:gradle项目,用AndroidStudio编写,不含测试代码
- client:maven项目,用IntelliJ编写,测试代码位于
- 配置
ANDROID_HOME
时,记得配至到系统默认的bash配置文件中。刚开始时自己只写到了~/.zshrc
里(因为平时用的是zsh),结果运行测试用例时报错找不到ANDROID_HOME
,上网查找后也没有结果(baidu检索出的中文博客大多是讲路径中不要有空格…),最后醍醐灌顶恍然大悟,改了~/.bash_profile
,才生效 - 在写Appium测试用例(Java)时,在EditText进行输入,直接
element.sendKeys("foooooo")
即可,不要想当然在前面加上element.click()
,否则会有奇怪的事情发生
maven依赖
1 | <dependencies> |
启动 Activity
由于Appium目前只能用包名+类名
的方式启动,不支持通过intent启动Activity。如果需要在启动中携带参数,这里提供一个解决方法:在debug面板中通过scheme直接进入目标Activity。这种做法过于依赖Debug面板,其实并不是一种好的实现方式。
希望Appium团队能够在后续更新中提供更多的启动Activity途径。
Appium中启动Activity的方法,代码位于AndroidDriver.java
1 | /** |
测试数据存取
对于如何读取mock数据,有两种思路
手机/模拟器连接mock服务器后,在mock服务器上配置,客户端每次请求会发送出去,但不是发送到真实的api后端,而是发送到mock服务器
- app代码无需变动
- 实现简单
- android/iOS两个平台可以共用同一套数据、同一个mock服务器
- 依赖mock服务器,甚至可能需要自己搭建mock服务器
- 要考虑如何使模拟器在mock服务器上进行注册。已有的扫二维码方式显然不现实
将mock数据存入手机/模拟器,本地读取
- 不依赖mock服务器
- 需要app内部支持,实现DB、Service等功能,较复杂
- android/iOS各自都需要改动底层代码以进行支持
- 仍然需要考虑正常开启的app如何自动切换到测试模式
比较后,选用1
作为最后的实现方式,同时基于mobile-httpwatch
搭建了自己的mock服务器,提供预加载配置的接口。
Show Time
主流程测试用例(预订):test case
这条用例的操作过程中,涉及到调用以下3个接口:
getbookingcontext.yy
,获取商户预订配置getbookingholidays.yy
,获取节假日信息(商户无关)book.yy
,下订单
出于简化的考虑,我们本次只对接口3
进行mock。
截图应如下所示:
输入
输出
Q: 预设的mock数据要保存在TestCase中还是保存在Server里?
有两种方案
- mock data 保存在 TestCase 侧,每次用例执行前,TestCase 把数据传给 Server(这种方案每次传递数据量过大)
- mock data 保存在 Server 侧,每次用例执行前,TestCase 把 mock data id 传给 Server
每个 case 对应一套 mock data ,可以是一个接口或者多个接口的数据。
功能点开发进度表
||状态|功能点|备注|
|1|done|test engine 发送 pre-req ,告知 server caseid||
|2|done|server 收到请求||
|3|done|server 解析请求中的 caseid||
|4|done|server 根据 caseid ,加载本地对应 mock data ,加载完成后告知 test engine||
|5|done|test engine 驱动 client 进行注册||
|6|done|test engine 驱动 client 发送真实请求||
|7|done|server 根据真实请求,返回已经准备好的 mock data||
|8|done|client 获得 mock data||
|9|done|test engine 进行自动化 UI 检验||
|10||test engine UI 校验完成后,发送 post-req,告知 server 清除 mock data|可选|
|11||server 接收到 post-req 后,清除 mock data|可选|
一些nodejs
函数方法
处理get
请求
1 | <!-- http://appmock.dp/mockconfig.do?caseid=1024 --> |
处理post
请求
1 | var postData = ""; |
读取文件(同步)
1 | var content = fs.readFileSync('/Users/leili/Downloads/7'); |
读取文件(异步)
1 | fs = require("fs"); |
遇到的问题
- 预订可能对已过时间有一些判断,导致在线预订页无法使用mock数据,原因未明
反过来,一些思考
真的需要自动化吗?UI 本身做的逻辑就很少,如果返回数据是正确的,UI 显示也几乎不会出现问题,为何要如此多精力来写自动化 case
- 准确度:每一个控件,展示什么内容?
- 数量:case 数量大,记不住
投入到生产中,会遇到的问题
- 前期准备量大:扒测试数据,造各种case(定金、预订成功、失败,商家营业中、暂未营业等各种状态)
- 难以对布局之间的相对位置、缩进等进行测试
- 即使是使用Appium进行自动化测试,也是需要rd做支持的,qa必须从rd处了解到诸如控件id等属性,方可以定位到目标控件进行操作。
- 视觉上看是一个TextView,而实际上是两个TextView,作为QA难以判断(可能要求理解功能具体实现)
mobile-httpwatch 项目阅读笔记
记录的内容比较琐碎
web.js 注册,设置mock数据
mockconfig.js mock设置界面
User.js 用户数据结构,每个用户有一个MockConfig
mock_config.js 默认的mock数值
html5 的 localStorage
ProxyFactory.js mock rule,重点看handleProxyRequest和mockResponse两个方法
mockConfig = user.getMockRuleForUrl(req.url)
Utils.js
参考资料
http://www.cnblogs.com/lori/p/3437562.html
http://www.mkyong.com/java/how-to-send-http-request-getpost-in-java