Monkey
Monkey 是运行在你的模拟器或者设备上一个程序,它能产生伪随机事件,如用户点击,触摸,用户手势(译者:gestures 指用户的连续动作导致屏幕的动态显示,Android 上可以使用手指“拉动”屏幕的效果就是 gesture), 以及一系列的系统级事件。你可以使用 Monkey 对你的程序进行压力测试,它可随机产生一些重复的东西。
1. 概述
Monkey 是一个命令行程序,你可以跑在模拟器或者设备上。它发送随机的用户和系统事件,可以对你开发的应用程序进行压力测试。
Monkey 包含一系列的选项,但可以分解为 4 个主要的类别:
- 基本设置选项,例如设置一些事件。
- 操作限制,如限制测试某一个单独的包。
- 事件类型以及频率。
- 调试选项。
当 Monkey 运行时,它产生的事件被发送给系统。它会监视正在测试系统并寻找三种情况做特殊处理:
- 如果你限制 Monkey 在一个或者多个包里运行,如果发现程序试图使用其它包,就对其进行阻塞。
- 如果你的程序崩溃或者收到任何无法处理的异常, Monkey 就会停止并且报告错误。
- 如果你的程序产生一个程序没有答复的错误, Monkey 会停止并报告错误。
根据选项的冗长程度,你可以看到 Monkey 运行时候产生的报告,这个时候事件已经开始产生。
2. Monkey 的基本用法
你可以通过命令或者脚本启动 Monkey 。因为 Monkey 运行在模拟器 / 设备里。你需要在这些环境的 shell 里启动它,使用时,在每个命令前加上 adb shell。
基本语法:
adb shell monkey [options] <event-count>
Bash
Copy
没有选项指定时, Monkey 安静(没有其它复杂内容)模式启动,然后发送事件给所有安装在你目标扳上的包里。
这里有一个有代表性的命令,它能启动你的程序并发送 500 个随机的事件给程序。
adb shell monkey -p io.github.liushilive.at -v 500
Bash
Copy
3. Monkey 压力测试实践
- 在手机 开发者选项 中,选中 USB 调试
- 确认手机与电脑连接:
adb devices
- 安装测试 APP:
adb install package.apk
- 获取 APP 包名:进入 Shell
adb shell
,筛选日志输出logcat | grep Displayed
oradb logcat | findstr START
- 给指定包打压力:
adb shell monkey -vvv --throttle 500 -p io.github.liushilive.at 1000 > monkey.txt 2>&1
-
分析日志
- 程序无响应的情况:搜索关键字
ANR
- 进入 adb shell:
adb shell
- 进入 anr 目录:
cd data/anr
- 查看
traces.txt
- 提取
traces.txt
文件:adb pull /data/anr/traces.txt
- 进入 adb shell:
- 崩溃、闪退的情况 1:搜索关键字
CRASH
- 崩溃、闪退的情况 2:搜索关键字
Exception
- 内存溢出的情况:搜索关键字
OOM
- 测试成功的情况:搜索关键字
Monkey finished
- 程序无响应的情况:搜索关键字
-
重现:
adb shell monkey -p io.github.liushilive.at -vvv -s 1546458727792 1000 > monkey1.txt 2>&1
- 加随机数种子:
adb shell monkey -vvv -p com.android.calculator2 -s 100 50
- 加延迟:
adb shell monkey -vvv -p com.android.calculator2 --throttle 1000 10
- 触摸事件:
adb shell monkey -vvv -p com.android.calculator2 --pct-touch 100 100
4. 日志解析
adb shell monkey -vvv -p io.github.liushilive.at --pct-touch 1 --pct-motion 2 --pct-pinchzoom 3 --pct-trackball 4 --pct-rotation 5 --pct-permission 6 --pct-nav 7 --pct-majornav 8 --pct-syskeys 9 --pct-appswitch 10 --pct-flip 11 --pct-anyevent 34 --throttle 100 100 > 1.txt 2>&1
Bash
Copy
4.1. 各事件的百分比
-
--pct-touch
0:触摸事件百分比(触摸事件是一个在屏幕单一位置的按下 - 抬起事件) -
--pct-motion
1:手势事件(手势事件是由一个在屏幕某处的按下事件、一系列的伪随机移动、一个抬起事件组成)即一个滑动操作,但是是直线的,不能拐弯 -
--pct-pinchzoom
2:二指缩放事件,放大缩小手势操作 -
--pct-trackball
3:轨迹事件 -
--pct-rotation
4:屏幕旋转事件 -
--pct-permission
5: 权限许可事件 -
--pct-nav
6:基本导航事件 -
--pct-majornav
7:主要导航事件 -
--pct-syskeys
8:系统按键事件 -
--pct-appswitch
9:启动 Activity 事件 -
--pct-flip
10:键盘事件 -
--pct-anyevent
11:其他类型事件
#随机种子数,执行事件数量
:Monkey: seed=1545952923355 count=100
#运行的应用列表
:AllowPackage: io.github.liushilive.at
#Category包含:LAUNCHER与MONKEY
:IncludeCategory: android.intent.category.LAUNCHER
:IncludeCategory: android.intent.category.MONKEY
#各事件的百分比
// Event percentages:
// 0: 1.0%
// 1: 2.0%
// 2: 3.0%
// 3: 4.0%
// 4: 5.0%
// 5: 6.0%
// 6: 7.0%
// 7: 8.0%
// 8: 9.0%
// 9: 10.0%
// 10: 11.0%
// 11: 34.0%
#执行的事件流信息
#启动APP事件
:Switch: #Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=cc.liushi.testapp/.HomeScreenActivity;end
// Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=cc.liushi.testapp/.HomeScreenActivity } in package cc.liushi.testapp
#点击事件
:Sending Touch (ACTION_DOWN): 0:(698.0,306.0)
:Sending Touch (ACTION_UP): 0:(703.8239,325.90808)
....
:Sending Touch (ACTION_UP): 0:(1184.9438,428.81464)
:Sending Trackball (ACTION_MOVE): 0:(4.0,0.0)
# 异常信息
// CRASH: cc.liushi.testapp (pid 2901)
// Short Msg: java.lang.ArithmeticException
// Long Msg: java.lang.ArithmeticException: divide by zero
# 机型和系统信息
// Build Label: Android/sdk_phone_x86/generic_x86:7.0/NYC/4174735:userdebug/test-keys
// Build Changelist: 4174735
// Build Time: 1499888857000
# crash详细信息
// java.lang.ArithmeticException: divide by zero
// at android.widget.SimpleMonthView.findClosestColumn(SimpleMonthView.java:550)
# Monkey执行结果信息
** Monkey aborted due to error.
Events injected: 437
:Sending rotation degree=0, persist=false
:Dropped: keys=1 pointers=0 trackballs=0 flips=0 rotations=0
## Network stats: elapsed time=9984ms (0ms mobile, 0ms wifi, 9984ms not connected)
** System appears to have crashed at event 437 of 1000 using seed 1515393057075
Bash
Copy
5. Android 平台 Monkey 测试标准
-
系统稳定性测试
-
测试样机数量:5-10 台
-
运行时间:25 小时
-
测试要求:
1) 运行时间》20 小时
2) 样机运行时间按从小到大排序,取中间 2 个值,计算平均时间,要求时间中间值平均为 24 小时
3) 以上两个条件均满足则认为通过测试(运 行过程中无异常)
-
-
单个 APK 运行稳定性测试
-
测试样机数量:5-10 台
-
运行时间:25 小时
-
测试要求:
平均运行时间至少为 20 小时(>380000 个 ENVENT), 测试过程中无 ANR、 JAVACRASH、NativeCrash、WindowLeak、 Exceeds VM budget count 等任何异常
-
6. 猴运行业内标准
最终发布前,Monkey 跑完的总次数应为 25W 次,其结果里不允许有 nullPointException 出现。
7. 命令选项参考
下面的表格里列出了所有包含在 Monkey 命令行的参数:
类别 |
选项 |
描述 |
通用 |
--help |
打印使用向导。 |
-v |
每个 -v 在命令里都会增加日志级别,0 级别(默认)在启动、测试结束、最终结果之外只提供很少的信息,1 级别在运行时提供更详细的测试信息,例如每个发往你活动的事件。 2 级别提供更加详细的设置信息,如一个活动是否选中被测试。 |
|
事件 |
-s <seed> |
随机数字产生器的种子。如果你用同样的种子运行 Monkey ,它将会产生相同的事件。 |
--throttle <milliseconds> |
在事件中插入一个固定的延迟。一般使用这个命令去延缓 Monkey 程序。如果没有指定, Monkey 产生的事件将没有延迟并尽可能快的发送。 |
|
--pct-touch <percent> |
调整触摸事件的比例。(触摸事件是一个在屏幕上单点按下的事件) |
|
--pct-motion <percent> |
调整手势事件的比例。(手势事件由一系列屏幕上的按下事件组成,一系列的伪随机移动和一个松开事件) |
|
--pct-trackball <percent> |
调整跟踪球事件(跟踪球由一个或多个随机移动事件组成,有时还会接一个单击事件) |
|
--pct-nav <percent> |
调整”基本”导航事件。(导航事件由上 / 下 / 左 / 右组成,这些事件由输入设备输入) |
|
--pct-majornav <percent> |
调整“主要”的导航事件的比例。(有些导航事件将会在你的 UI 里导致一些动作,例如在 5 向键里的中间,退出键,或者菜单键) |
|
--pct-syskeys <percent> |
调整“系统”事件的比例。(有些键通常是系统保留的,如 主界面,退出,电话,结束通话,或者声音调节 ) |
|
--pct-appswitch <percent> |
调整活动被运行的比例。 在一些随机的间隔里, Monkey 会调用一个 startActivity()的调用,以最大程序得覆盖你包里的所有的活动。 |
|
--pct-anyevent <percent> |
调整其他类型事件的比例。 这包含所有其他的事件,如用户按键,其他设备上不常用的的按键,等等。 |
|
限制 |
-p <allowed-package-name> |
如果你指定一个或者多个包, Monkey 程序仅仅允许系统访问这些包里的活动。如果你的应用程序需要进入其他包的活动(例如选择一个联系人),你也需要指定这个包。如果你不指定任何包, Monkey 将允许系统运行所有包里活动。 指定多个包,可以多次使用 -p 选项 —— 一个—每个 p 选项选一个包。 |
-c <main-category> |
如果你指定一个或多个类别(category), Monkey 将仅仅允许系统访问这些指定类别里的一个活动。如果你不指定任何类别, Monkey 将选择 Intel.CATEGORY _LAUNCHER 或者 CATEGORY_MONKEY 列出的活动。如果要选择多个类别,多次使用 -c 选项 —— 每个 -c 选一个类别。 |
|
调试 |
--dbg-no-events |
当被指定时, Monkey 将在测试活动里执行初始化运行程序,但还没有产生任何事件。 最好的是集成 -v, 能使一个或多个包被限制,这样一个非 0 的控制能保证 Monkey 程序运行 30 秒或更长时间。这提供一个环境,你可以监视你的应用程序调用的包的所有变化。 |
--hprof |
如果设置这个选项,系统会在 Monkey 事件序列前后都立即产生程序分析报告。这将会产生巨大的(~5M)数据文件,所以请谨慎使用。 |
|
--ignore-crashes |
通常情况下, Monkey 会因为程序崩溃或者遇到一些无法处理的异常而停止,但你指定了这个选项, Monkey 会继续发事件给系统,直到事件计数器结束。 |
|
--ignore-timeouts |
通常情况下, Monkey 会因为程序超时而停止,例如程序弹出“应用程序没有答复”的对话框。如果你指定了这个选项, Monkey 会继续发事件给系统,直到事件计数器结束。 |
|
--ignore-security-exceptions |
通常情况下, Monkey 会因为一些权限错误而停止,例如,它试图运行一个需要特殊权限的活动。 如果指定这个选项, Monkey 会继续发送事件给系统,直到事件计数器结束。 |
|
--kill-process-after-error |
通常情况下, Monkey 会因为错误停止,应用程序失败但会并停留在运行状态,当这个条件设置后,它会发消息给系统在错误发生的地方停止进程。 评注:在程序正常(成功)的完成,运行的程序不会停止,设备会收到结束事件而停留在最后的状态上。 |
|
--monitor-native-crashes |
监视并报告 Android 系统代码里的崩溃事件。如果设置了 --kill-process-after-error, 系统将会停止。 |
|
--wait-dbg |
停止 Monkey 直到调试工具连接上程序。 |