现在 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 提高遍历效率

由于 Monkey 本质上是无脑交互,在实际使用中,很容易由于进入了一些 App 场景后在里面转悠几十分钟都出不来,大大影响了遍历效率。以下经验和大家分享:

  1. 不要从全新安装的 App 安装开始遍历 很多人的方案开头就是自动 adb 安装 App,其实这样效果很差,因为全新安装后会出现大量的低频新手教程、登录、权限弹框等影响 Maxim。而稳定性测试本质上是模拟老用户长时间使用 App 的情况,所以应当已经完全登录,新手流程已经全部过掉的情况下再开始 Maxim。具体实施的时候有几种选择:a. 手工安装 app,登录,过掉已知的新手教程 b. 始终不清除稳定性测试设备上 app 的数据,较新的开发版 App 可以更新安装保持数据 c. 如果 b 不容易实现,可以试试 adb backupadb restore 保存和复原 App 数据
  2. 避免动态权限弹框 动态权限弹框也是影响 Maxim 执行的很大因素,各个厂商弹框不同,很难适配。因此在开始 Maxim 遍历前,应当赋予 App 所有需要的权限,这步可以手工,也可以用adb pm grant <包名> <权限名>来自动实现。
  3. 关掉输入法 遍历过程中无可避免会点击到各种输入框,输入法会弹起,一旦 Maxim 点击到输入法,例如某狗,某度输入法,会导致非常多不可预料的情况,比如输入法广告弹框,录音弹框等等。而且 Maxim 遍历时如果要输入内容,也是直接输入并非通过输入法,所以输入法是一个纯干扰,最简单的方式就是在开始遍历前关掉输入法,结束后再开启。具体实现时,安装 Appium Keyboard(也就是啥也没有),然后 通过adb shell ime 来设置输入法
  4. 黑名单屏蔽 Activity 和控件
    Maxim 提供了两个级别的禁止遍历黑名单,可以通过配置直接禁止进入某些 Activity,也可以通过配置屏蔽指定 Activity 上的区域(xpath 或者坐标范围)。Activity 黑名单原理是截获切换的 Intent 直接不发,Appetizer 提供的图形化方案可以非常简单地设置 Activity 黑名单:

    屏蔽的规则很简单,一般屏蔽一切非 App 业务的第三方推送、第三方支付、第三方登录、分享、扫码、人脸识别、图片/文件选择器、人工客服。而区域屏蔽则更为精细,应当屏蔽三方登录按钮区域、付费选择、广告、分享按钮等一切能够切出 App 或者需要人工/摄像头的功能点。登录和支付业务不应该在稳定性测试中出现,应该是登录专项和支付业务用例里。

    max.widget.black配置项是一个数组,每一项一条屏蔽规则,规则很容易懂,指定某个 Activity 以及需要屏蔽的控件的 xpath,或者屏幕像素区域 bounds 或者有多个符合 xpath 条件的控件条件下增加 index 表示第几项

  5. 调整事件比例
    Maxim MIX 模式下默认会有 30% 完全随机事件(屏幕任意位置乱点、滑动、任意物理按键)+ 70% 界面元素解析后的元素级交互,在用于 App 稳定性测试过程中,比例应当根据 App 特性进行调整。Maximw 从 Google 原生 Monkey 改来,完全兼容 Monkey 的参数,如下:

  6. 多个配置结合
    配置不可能一蹴而就,也不用纠结在单个配置上。可以分几次跑,每次入口的 Activity 不一样,然后参数不一样来达到综合做好的情况。例如主界面有多个主业务入口,可以每个主业务入口 Activity 用一套配置,每套配置里面把主界面黑名单掉,这样就不会回退回来。Appetizer 存取多个配置:

  7. 处理表单类界面
    表单类界面即有多个输入框,然后按钮,而按钮成功要求多个输入框满足一个验证条件,例如都要有内容。表单类界面是 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 个小时即可。

稳定性测试要捕获什么,可以捕获什么

  1. crash, ANR
  2. 主线程卡顿

  3. http 请求 4xx 5xx,以及高延迟的情况

  4. 截图
    Maxim 支持每次执行事件后截图,还支持保存页面控件结构(XML),截图上会有事件点击的红点标注,方便发现问题后回溯到具体场景,具体字 max.config 里开启,如下图。注意,截图保存在 /sdcard/max-output 目录,长时间运行会占据大量的存储控件,确保每次运行前用 Appetizer 下载上次的截图结果,并删除

如何拓展稳定性测试,让同样的测试时间产出更大

很多时候第一次引入稳定性测试后会发现一些问题,积极性会比较高,随着时间推移,问题会发现越来越少,换个方面考虑是 App 低级错误越来越少,这时候会面临继续投入稳定性测试的质疑,这方面有几点:

  1. 稳定性测试和回归是一样的,是守门员,非前锋,目标是拦截不是预言,
  2. 自动遍历其实会高速发出 UI 事件,对 App 性能也是一个考验,所以自然可以收集并分析性能数据,在稳定性测试的框架上分析性能瓶颈。 具体怎么做,请期待 6.28-6.29 的 MTSC 2019 大会,将在 6.29 周六下午 1 点 QA 场与大家分享

Appetizer 之后会带来什么样更方便的稳定性测试

目前 Appetizer 为 1.4.3,未来版本:

关注 Appetizer 微信服务号,了解最新的测试技术方案和 Appetizer 功能预告


↙↙↙阅读原文可查看相关链接,并与作者交流