现在 App 普遍可以运行在后台,在用户切换到的时候唤醒到前台,一方面可以避免不必要的冷启动时间,另一方面可以持续接收服务端的推送。
前后台运行时间加起来可以长达几十小时,甚至几百小时,所以对于 App 长时间使用的稳定性有了更高的要求,需要 App 稳定性测试来避免长时间运行下的偶发闪退、内存泄露、性能变差等等。
通常 App 稳定性测试采用 Monkey 类的工具来长时间全自动遍历 App,并捕获期间发生的稳定性问题。综合各个 Monkey 方案的稳定性、可配置性、执行效率等多方面考虑,首选Maxim作为 Monkey 遍历工具,通过Appetizer管理和配置 Maxim 提高方案试错效率。稳定性测试方案有以下重点,本文将一一解答:
Google 原生 Monkey 是一个命令行工具,可以全自动随机点击屏幕,用来测试 App 稳定性等。Maxim 是 @zhangzhao_lenovo 修改自 monkey 的高级版本,支持 Android 5.0-9.0
、操作非常高速(10-15 事件/秒),稳定性高,可配置。 AppetizerIO提供了对 Maxim 的深度集成,使得配置更方便,配置管理更简单。从 Appetizer 导航 -> 自动化测试 -> Maxim,最基本配置选好测试设备和测试 APK 即可开始测试。Maxim 提供的配置有:
Maxim 的遍历模式,如图
Activity 黑白名单,选择待测 APK 后会出现选择,下文有截图
测试时长,可以根据时间(分钟)或者自动产生的事件数
max.xpath.actions
指定界面确定性步骤,例如登录
max.widget.black
屏蔽某些界面的某些控件或者区域,例如屏蔽广告区域
max.config
开启定时截图;调整启动等待时间
事件间延迟:两次事件间隔的时间
Maxim 事件日志
数据采集和输出路径:Appetizer 可以在测试过程中收集额外数据,例如 Maxim 日志、logcat,Battery Historian 数据等等
由于 Monkey 本质上是无脑交互,在实际使用中,很容易由于进入了一些 App 场景后在里面转悠几十分钟都出不来,大大影响了遍历效率。以下经验和大家分享:
adb backup
和 adb restore
保存和复原 App 数据adb pm grant <包名> <权限名>
来自动实现。adb shell ime
来设置输入法黑名单屏蔽 Activity 和控件
Maxim 提供了两个级别的禁止遍历黑名单,可以通过配置直接禁止进入某些 Activity,也可以通过配置屏蔽指定 Activity 上的区域(xpath 或者坐标范围)。Activity 黑名单原理是截获切换的 Intent 直接不发,Appetizer 提供的图形化方案可以非常简单地设置 Activity 黑名单:
屏蔽的规则很简单,一般屏蔽一切非 App 业务的第三方推送、第三方支付、第三方登录、分享、扫码、人脸识别、图片/文件选择器、人工客服。而区域屏蔽则更为精细,应当屏蔽三方登录按钮区域、付费选择、广告、分享按钮等一切能够切出 App 或者需要人工/摄像头的功能点。登录和支付业务不应该在稳定性测试中出现,应该是登录专项和支付业务用例里。
max.widget.black
配置项是一个数组,每一项一条屏蔽规则,规则很容易懂,指定某个 Activity 以及需要屏蔽的控件的 xpath,或者屏幕像素区域 bounds 或者有多个符合 xpath 条件的控件条件下增加 index 表示第几项
调整事件比例
Maxim MIX 模式下默认会有 30% 完全随机事件(屏幕任意位置乱点、滑动、任意物理按键)+ 70% 界面元素解析后的元素级交互,在用于 App 稳定性测试过程中,比例应当根据 App 特性进行调整。Maximw 从 Google 原生 Monkey 改来,完全兼容 Monkey 的参数,如下:
--pct-touch <percent>
为单击事件百分比--pct-motion <percent>
为滑动事件百分比(方向、长度和速度随机)--pct-trackball <percent>
随机滚动后点击事件百分比--pct-nav <percent>
上下左右滑动事件--pct-majornav <percent>
回退、home、最近三键--pct-syskeys <percent>
系统按键,标准三键 + 音量等--pct-appswitch <percent>
切换 App
实际使用中,非 0 项目应该为 --pct-touch
--pct-motion
--pct-majornav
,其中 touch 可以低一些,因为毕竟有元素级别 touch 乱点没有特别大的意义;motion 可以高一点,弥补 Maxim 不会滑动的缺陷;majornav 中等,保证有一定量的回退;推荐使用 5,20,10;
多个配置结合
配置不可能一蹴而就,也不用纠结在单个配置上。可以分几次跑,每次入口的 Activity 不一样,然后参数不一样来达到综合做好的情况。例如主界面有多个主业务入口,可以每个主业务入口 Activity 用一套配置,每套配置里面把主界面黑名单掉,这样就不会回退回来。Appetizer 存取多个配置:
处理表单类界面
表单类界面即有多个输入框,然后按钮,而按钮成功要求多个输入框满足一个验证条件,例如都要有内容。表单类界面是 Maxim 和 Monkey 类工具非常不适合的一种界面,随机能够满足验证条件的概率极低,基本没有探索价值。可以直接黑名单,或者通过 max.xpath.actions
配置项直接填写。
覆盖率大致方向有两个,Jacoco(代码行覆盖)和 Activity 覆盖率,Jacoco 需要 源代码接入,完全落地需要一定时间。在配置初期,并不用太强调代码行覆盖率,毕竟 Maxim 有一定的随机性,多次跑可能导致不同的结果。在配置初期,可以以 Activity 覆盖率作为主要参考,力求尽量覆盖到可以自动化遍历的业务 Activity。
Activity 覆盖率获取方式有两种:如果 APK 经过 Appetizer 插桩,每次 Maxim 运行后都会有 Appetizer 插桩数据报告,里面有 Activity 覆盖率以未覆盖的 Activity 名单;如果没有插桩,可以用 Appetizer 保存 Maxim 运行产生的 stdout,然后自行 parse 进入过的 Activity。
当配置优化后,同时 Jacoco 方案已经成熟的情况下,可以评估一次完整的稳定性测试的代码行覆盖情况。一般来说行覆盖率不会很高,原因有几个部分 1. Jacoco 统计分母是所有的 class,有很多三方代码和库代码是 dead code 实际不会执行,除非 Jacoco 分析的时候就去掉的这些 2. 毕竟 Maxim 遍历没有逻辑性,很多和数据相关的代码块并不能有效进入 3. 单机型运行的话,有些安卓版本特殊的代码也会遗漏;总体来说,行覆盖仅仅做参考,配置优化能增加就是好事,不必苛求一个具体百分比目标。
遍历时间并不是越长越好,因为执行初期对覆盖率提升非常有效,而后期大量的时间对两种覆盖率的提升都是非常有限。另一方面来说,遍历时长太久大大增加了收集到的数据量,影响分析效率,也会引入不必要稳定性坑。应当多花费时间优化配置,帮助 Maxim 省去非常多的不可控性和徒劳遍历,一般一套优化过的配置,只需要 20 分钟到 1 个小时即可。
/sdcard/maxim-output/crash.log
,注意这些只是疑似情况主线程卡顿
http 请求 4xx 5xx,以及高延迟的情况
截图
Maxim 支持每次执行事件后截图,还支持保存页面控件结构(XML),截图上会有事件点击的红点标注,方便发现问题后回溯到具体场景,具体字 max.config 里开启,如下图。注意,截图保存在 /sdcard/max-output
目录,长时间运行会占据大量的存储控件,确保每次运行前用 Appetizer 下载上次的截图结果,并删除
很多时候第一次引入稳定性测试后会发现一些问题,积极性会比较高,随着时间推移,问题会发现越来越少,换个方面考虑是 App 低级错误越来越少,这时候会面临继续投入稳定性测试的质疑,这方面有几点:
目前 Appetizer 为 1.4.3,未来版本:
关注 Appetizer 微信服务号,了解最新的测试技术方案和 Appetizer 功能预告