原生Monkey

一、 什么是Monkey

Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等),实现对正在开发的应用程序进行压力测试。

Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。

二、 Monkey的特征

  1. 测试的对象仅为应用程序包,有一定的局限性。

  2. Monky测试使用的事件流数据流是随机的,不能进行自定义。

  3. 可对MonkeyTest的对象,事件数量,类型,频率等进行设置。

三、Monkey的基本用法

基本语法如下:

adb shell monkey [options]

options选项(adb -d shell monkey):

usage: monkey [-p ALLOWED_PACKAGE [-p ALLOWED_PACKAGE] ...]
              [-c MAIN_CATEGORY [-c MAIN_CATEGORY] ...]
              [--ignore-crashes] [--ignore-timeouts]
              [--ignore-security-exceptions]
              [--monitor-native-crashes] [--ignore-native-crashes]
              [--kill-process-after-error] [--hprof]
              [--pct-touch PERCENT] [--pct-motion PERCENT]
              [--pct-trackball PERCENT] [--pct-syskeys PERCENT]
              [--pct-nav PERCENT] [--pct-majornav PERCENT]
              [--pct-appswitch PERCENT] [--pct-flip PERCENT]
              [--pct-anyevent PERCENT]
              [--pkg-blacklist-file PACKAGE_BLACKLIST_FILE]
              [--pkg-whitelist-file PACKAGE_WHITELIST_FILE]
              [--wait-dbg] [--dbg-no-events]
              [--setup scriptfile] [-f scriptfile [-f scriptfile] ...]
              [--port port]
              [-s SEED] [-v [-v] ...]
              [--throttle MILLISEC] [--randomize-throttle]
              COUNT

如果不指定options,Monkey将以无反馈模式启动,并把事件任意发送到安装在目标环境中的全部包。下面是一个更为典型的命令行示例,它启动指定的应用程序,并向其发送9999个伪随机事件:
adb shell monkey -p your.package.name -v 9999

参数示例

Monkey命令参数介绍

  1. 参数: -p
    参数-p用于约束限制,用此参数指定一个或多个包(Package,即App)。指定
    包之后,Monkey将只允许系统启动指定的APP。如果不指定包,Monkey将允许系统启动设备中的所有APP。

  • 指定一个包: adb shell monkey -p com.htc.Weather 100
    说明:com.htc.Weather为包名,100是事件计数(即让Monkey程序模拟100次随机用户事件)。

  • 指定多个包:adb shell monkey -p com.htc.Weather –p com.htc.pdfreader -p com.htc.photo.widgets 100

  • 不指定包:adb shell monkey 100
     说明:Monkey随机启动APP并发送100个随机事件。

  1. 参数: -v
    用于指定反馈信息级别(信息级别就是日志的详细程度),总共分3个级别,分别对应的 参数如下表所示:

    日志级别 Level 0
    示例 adb shell monkey -p com.htc.Weather –v 100
    说明 缺省值,仅提供启动提示、测试完成和最终结果等少量信息

    日志级别 Level 1
    示例 adb shell monkey -p com.htc.Weather –v -v 100
    说明 提供较为详细的日志,包括每个发送到Activity的事件信息

    日志级别 Level 2
    示例 adb shell monkey -p com.htc.Weather –v -v –v 100
    说明 最详细的日志,包括了测试中选中/未选中的Activity信息

  2. 参数: -s
    用于指定伪随机数生成器的seed值,如果seed相同,则两次Monkey测试所产生的事件序列也相同的。

  • 示例:
    Monkey测试1:adb shell monkey -p com.htc.Weather –s 10 100
    Monkey 测试2:adb shell monkey -p com.htc.Weather –s 10 100
    两次测试的效果是相同的,因为模拟的用户操作序列(每次操作按照一定的先后顺序所组成的一系列操作,即一个序列)是一样的。操作序列虽然是随机生成的,但是只要我们指定了相同的Seed值,就可以保证两次测试产生的随机操作序列是完全相同的,所以这个操作序列伪随机的;

  1. 参数: --throttle <毫秒>
    用于指定用户操作(即事件)间的时延,单位是毫秒;

  • 示例:adb shell monkey -p com.htc.Weather –throttle 3000 100

  1. 参数: --ignore-crashes
    用于指定当应用程序崩溃时(Force & Close错误),Monkey是否停止运行。如果使用此参数,即使应用程序崩溃,Monkey依然会发送事件,直到事件计数完成。

  • 示例1:adb shell monkey -p com.htc.Weather --ignore-crashes 1000
    测试过程中即使Weather程序崩溃,Monkey依然会继续发送事件直到事件数目达到1000为止;

  • 示例2:adb shell monkey -p com.htc.Weather 1000
    测试过程中,如果Weather程序崩溃,Monkey将会停止运行。

  1. 参数: --ignore-timeouts
    用于指定当应用程序发生ANR(Application No Responding)错误时,Monkey是否停止运行。如果使用此参数,即使应用程序发生ANR错误,Monkey依然会发送事件,直到事件计数完成。

  2. 参数: --ignore-security-exceptions
    用于指定当应用程序发生许可错误时(如证书许可,网络许可等),Monkey是否停止运行。如果使用此参数,即使应用程序发生许可错误,Monkey依然会发送事件,直到事件计数完成。

  3. 参数: --kill-process-after-error
    用于指定当应用程序发生错误时,是否停止其运行。如果指定此参数,当应用程序发生错误时,应用程序停止运行并保持在当前状态(注意:应用程序仅是静止在发生错误时的状态,系统并不会结束该应用程序的进程)。

  4. 参数: --monitor-native-crashes
    用于指定是否监视并报告应用程序发生崩溃的本地代码。

  5. 参数: --pct-{+事件类别} {+事件类别百分比}
    用于指定每种类别事件的数目百分比(在Monkey事件序列中,该类事件数目占总事件数目的百分比)

参数:
使用说明:
示例:

  • –pct-touch {+百分比}
    调整触摸事件的百分比(触摸事件是一个down-up事件,它发生在屏幕上的某单一位置)
    adb shell monkey -p com.htc.Weather --pct-touch 10 1000

  • –pct-motion {+百分比}
    调整动作事件的百分比(动作事件由屏幕上某处的一个down事件、一系列的伪随机事件和一个up事件组成)
    adb shell monkey -p com.htc.Weather --pct-motion 20 1000

  • –pct-trackball {+百分比}
    调整轨迹事件的百分比(轨迹事件由一个或几个随机的移动组成,有时还伴随有点击)
    adb shell monkey -p com.htc.Weather --pct-trackball 30 1000

  • –pct-nav {+百分比}
    调整“基本”导航事件的百分比(导航事件由来自方向输入设备的up/down/left/right组成)
    adb shell monkey -p com.htc.Weather --pct-nav 40 1000

  • –pct-majornav {+百分比}
    调整“主要”导航事件的百分比(这些导航事件通常引发图形界面中的动作,如:5-way键盘的中间按键、回退按键、菜单按键)
    adb shell monkey -p com.htc.Weather --pct-majornav 50 1000

  • –pct-syskeys {+百分比}
    调整“系统”按键事件的百分比(这些按键通常被保留,由系统使用,如Home、Back、Start Call、End Call及音量控制键)
    adb shell monkey -p com.htc.Weather --pct-syskeys 60 1000

  • –pct-appswitch {+百分比}
    调整启动Activity的百分比。在随机间隔里,Monkey将执行一个startActivity()调用,作为最大程度覆盖包中全部Activity的一种方法
    adb shell monkey -p com.htc.Weather --pct-appswitch 70 1000

  • –pct-anyevent {+百分比}
    调整其它类型事件的百分比。它包罗了所有其它类型的事件,如:按键、其它不常用的设备按钮、等等
    adb shell monkey -p com.htc.Weather

  • –pct -anyevent 100 1000* 指定多个类型事件的百分比:
    adb shell monkey -p com.htc.Weather --pct-anyevent 50 --pct-appswitch 50 1000
    注意:各事件类型的百分比总数不能超过100%;

四、log文件配置

log文件配置

  1. 首先对于monkey运行的日志文件命名需要有相应的规范。

  • 建议将monkey命令运行期间产生的level1级别的日志(2V)的日志文件名命名为verbose.txt;主要用来观看日志信息和时间分布信息

  • 建议将monkey命令运行期间产生的level2级别的日志(3V)的日志文件名命名为error.txt;主要是用来查看error的信息,做进一步的bug分析。

Code

description

2>/sdcard/error.txt

Level 2日志保存到sdcard上的error.txt中

1>/sdcard/verbose.txt

Level 1日志保存到sdcard上的verbose.txt中

  1. 需要在monkey命令行中添加dos命令将monkey命令运行的内容重定向到日志文件中。

adb shell monkey -p jixiang.com.myandroid --ignore-crashes --ignore-timeouts --ignore-native-crashes --pct-motion 60 -v -v --throttle 200 -s 200 1000 2>d:/error.txt 1>d:/verbose.txt

monkey命令行解释:此monkey命令行表示将monkey命令运行期间产生的level2级别的日志(运行程序期间产生的错误日志,类比python中的日志级别error)重定向至d:/error.txt文件中;
将monkey命令运行期间产生的level1级别的日志(运行程序期间的正常日志,类比python中的日志级别info)重定向至d:/verbose.txt文件中。

adb shell monkey -p jixiang.com.myandroid --ignore-crashes --ignore-timeouts --ignore-native-crashes --pct-motion 60 -v -v --throttle 200 -s 200 1000 "2>/sdcard/error.txt 1>/sdcard/verbose.txt"

若是使用PC运行monkey命令并保存在PC端,则在monkey命令的重定向处不需加" “,但是若是需要将monkey命令运行产生的日志信息保存在手机文件夹中,需要添加” "将monkey命令行中的重定向到日志文件的部分引起来

五、Monkey测试结果分析

在Monkey测试过程中可能会出现程序崩溃(CRASH)和程序无响应的情况(ANR),要将测试的log信息获取到,从而解决bug。
测试过程中出现crash现象时,根据seed值来完成bug的复现:
adb shell monkey -p (包名) -s (seed值) -v 1000
测试过程中出现ANR现象,会输出相应的信息,以ANR开头,获取到信息进行问题的解决,同样可以通过seed来进行复现adbshell cd /data/anr切换到设备路径下ls可以看到traces.txt里面即为log信息。
image
其中:

:Monkey: seed=200 count=1000    # seed为随机数生成器seed值,count为本次设置的操作次数
:AllowPackage: com.changan.facein   # 后面为指定测试的包名
# monkey进程的category
:IncludeCategory: android.intent.category.LAUNCHER  
:IncludeCategory: android.intent.category.MONKEY

紧接着其后面就是一个数据列表,是用来展示本次monkey测试所有随机事件类型的百分比:

* Event percentages本次测试的事件分布频率
* 0:触摸事件百分比,即参数–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:Activity启动事件百分比,即参数–pct-appswitch 
*10:键盘翻转事件百分比,即参数–pct-flip 
*11:其他事件百分比,即参数–pct-anyevent

// Event percentages:
//   0: 6.6666665%
//   1: 60.0%
//   2: 0.8888889%
//   3: 6.6666665%
//   4: -0.0%
//   5: -0.0%
//   6: 11.111112%
//   7: 6.6666665%
//   8: 0.8888889%
//   9: 0.8888889%
//   10: 0.44444445%
//   11: 5.7777777%

紧跟其后的就是一个个switch的内容,截取一段解释:

#  swicth的意义是表示Monkey命令此时在此安卓应用程序的具体哪个界面进行测试
Switch: #Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.changan.facein/.activity.WelcomeActivity;end
    // Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.changan.facein/.activity.WelcomeActivity } in package com.changan.facein
    // Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.changan.facein/.activity.WelcomeActivity } in package com.changan.facein

#  motion时间,以及motion参数
:Sleeping for 200 milliseconds
:Sending Key (ACTION_DOWN): 21    // KEYCODE_DPAD_LEFT
:Sending Key (ACTION_UP): 21    // KEYCODE_DPAD_LEFT

在verbose.txt日志文件结尾处一般会有以下内容:

#  Events injected 截止次数
Events injected: 1000
:Sending rotation degree=0, persist=false
:Dropped: keys=0 pointers=0 trackballs=0 flips=2 rotations=0

#  整个测试完成持续时间为42539ms。(1s=1000ms)
Network stats: elapsed time=42539ms (0ms mobile, 0ms wifi, 42539ms not connected)

#  monkey测试结束标识
// Monkey finished

verbose.txt日志文件到此标记着level1级别日志的结束,即monkey命令运行结束。

error.txt 错误日志

  • error.txt日志文件为monkey命令运行期间产生的安卓应用程序运行错误的日志;

  • 当monkey命令运行在安卓设备或者模拟器上没有出现应用程序运行错误的时候,此文件会为空;一旦运行monkey命令期间安卓应用程序发生错误,会将错误的部分日志内容重定向至error.txt日志文件中。

  • 在运行monkey命令以达到测试安卓应用程序稳定性的时候,最好是通过monkey的命令行参数忽略安卓应用程序可能发生的错误,让程序可以继续运行下去,monkey命令同样可以运行下去。【monkey命令运行期间应用程序发生错误不影响错误日志重定向至error.text日志文件】

monkey测试检测到的安卓应用程序错误类型分为三种:

  • CRASH:系统崩溃日志,当Apk存在崩溃的情况下会反馈相应的数据。

  • ANR:当ANR情况出现时,会反馈相应的数据。

  • 常见的Exception:进行monkey测试时,应用程序存在一些Exception同样会反馈相应的异常数据。

六、monkeyscript

monkeyscript是monkey的脚本语言,是一组可以被monkey识别的命令集合,可以帮我们完成一系列的被固定的重复性操作,monkey通过脚本来进行测试,只是一个记事本文件,缺点是在坐标、按键等方面没有逻辑性。
例: 启动app,搜索1次,退出。重复1万次
Script:

type=user
count=10
speed=1.0
start data >> 
LaunchActivity(com.sogou.activity.src, com.sogou.search.entry.EntryActivity)
UserWait(3000)
captureDispatchPointer(10,10,0,500,500,1,1,-1,1,1,0,0)
captureDispatchPointer(10,10,1,500,500,1,1,-1,1,1,0,0)
UserWait(500)
captureDispatchString(test)
UserWait(500)
captureDispatchPress(66)
UserWait(3000)
Drag(500,1500,500,500,500)
captureDispatchPress(4)
UserWait(1000)
captureDispatchPress(4)
captureDispatchPress(4)

script逐行解释:

type=user
count=10
speed=1.0
start data >> 
#固定头部,参数和值均不影响脚本
LaunchActivity(com.sogou.activity.src, com.sogou.search.entry.EntryActivity)
#启动app,参数1:包名,参数2:主activity名
UserWait(1500)
#等待1500毫秒
captureDispatchPointer(10,10,0,500,500,1,1,-1,1,1,0,0)
#按下坐标500,500(搜索框位置)
captureDispatchPointer(10,10,1,500,500,1,1,-1,1,1,0,0)
#抬起坐标500,500(搜索框位置)
UserWait(500)
#等待500毫秒
captureDispatchString(test)
#在搜索框输入“test”
captureDispatchPress(66)
#输入回车进行搜索
UserWait(3000)
#等待3000毫秒
Drag(500,1500,500,500,500)
#上划浏览搜索结果页
captureDispatchPress(4)
#输入back回退至app首页
UserWait(500)
等待500毫秒
captureDispatchPress(4)
captureDispatchPress(4)
#双back退出app

运行:
1.将脚本保存命名(例test_search)
2.将脚本文件放置测试机中

adb shell mkdir /sdcard/script
#创建脚本文件夹
adb push test_search /sdcard/script
#将脚本文件push到文件夹
3.运行脚本文件1万次

adb shell monkey -f /sdcard/script/test_search 10000

Monkeyscript API介绍

- LaunchActivity(pka name.cl name);启动应用的Activity。参数:包名和启动Activity
- Tap(x,y,tapDuration):模拟一次手指单击事件。参数:x,y为控件坐标,tapDuration为点击的持续时间,此参数可省略。
- DispatchPress(keyName):按键。参数:keycode
- RotateScreen(rotationDegree,persist):旋转屏幕。参数:rotationDegree为旋转角度 e.g.1代表90 
度;persist表示施转之后是否固定,0表示旋转后恢复,非0则表示固定不变。
- DispatchFlip(true/false);打开或者关闭软键盘 
- LongPress():长按2秒
- PressAndHold(x,y,pressDuration):模拟长按事件 
- DispatchString(input):输入字符串。
- Drag(xStart,yStart,xEnd,yEnd,stepCount);用于模拟一个拖拽操作。
- PinchZoom(x1Start,y1Start,x1End,y1End,x2Start,y2Start,x2End,y2End,stepCount):模拟缩放手势。
- UserWait(sleepTime):休眠一段时间 
- DeviceWakeUp():唤醒屏幕。
- PowerLog(power log type, test case status):模拟电池电量信息。 
- WriteLoq():将电池信息写入sd卡。 
- RunCmd(cmd):运行shell命令。
- DispatchPointer(downtime,eventTime,action,x,yxpressure,size,metastate,xPrecision,yPrecisio n,device,edgeFlags):向指定位置,发送单个手势。
- DispatchPointer(downtime,eventTime,action,x,yxpressure,size,metastate,xPrecision,yPrecisio n,device,edgeFilags):发送按键消息。
- LaunchInstrumentation(test name,runner name):运行一个instrumentation测试用例 
- DispatchTrackball:模拟发送轨迹球事件。 ProfileWait: 等待5秒
- StartCaptureFramerate():获取额率。
- EndCaptureFramerate(input):结束获取帧率

App Crawler

Monkey是Android平台上进行压力稳定性测试的工具,通过Monkey可以模拟用户触摸屏幕、滑动、按键等伪随机用户事件来对设备上的程序进行压力测试。而原生的Android Monkey存在一些缺陷:

事件太过于随机,测试有效性大打折扣
由于Monkey主要发送一些随机事件来进行测试,测试过程中的事件操作不受控制,大部分操作是无效的(比如点击的是空白区域、在不能滑动的页面进行滑动等等)。

对App页面内的控件覆盖率不佳
也是因为随机性这一特点,不能保证App页面的所有控件都能得到有效覆盖测试。

有概率跳出测试
点击到通知栏或者状态栏,就会跳转到其他的页面,从而中断当前App的测试。

Google官方推出的App遍历工具,相比Monkey基于伪随机的事件,App Crawler是基于控件的遍历,可以更好的去遍历App的功能。
https://developer.android.google.cn/training/testing/crawler

使用入门

在开始之前,请确保您具有最新版本的 Android SDK,它随附于 Android Studio。如果您安装独立的 Android SDK,请确保它包含最新的构建工具和平台工具。
然后,下载crawler二进制文件
接下来,启动模拟器或使用 USB 线连接实体设备。通过运行以下命令来确认设备已连接:

adb devices

如需调用crawler,请先将归档提取到您选择的目录中。从该目录中,使用以下命令调用crawler:

 java -jar crawl_launcher.jar --apk-file path/to/my/app.apk --android-sdk path/to/my/android/sdk

App Crawler运行完成后会生成 crawl_output 目录,里面有遍历的每一步的截图和日志信息。

相关命令参数:
选项 说明

  • –android-sdk path

  • 指定 Android SDK 的路径。这是一个必需的标记。

  • –apk-file file

  • 指定应用 APK 的路径,应用抓取工具随后会对其进行安装和抓取。这是一个必需的标记(如果未指定 --app-package-name)。

  • –app-package-name name

  • 指定应用的软件包名称。当您的应用已安装在设备上且无需重新安装时,使用此选项。这是一个必需的标记(如果未指定 --apk-file)。

  • –key-store path

  • 指定用于为您的应用和抓取工具 APK 签名的密钥库的路径。当您的应用需要特定签名才能正常运行时,使用此选项。

  • –key-store-password password

  • 指定您为 --key-store 选项提供的密钥库的密码。这是一个必需的标记(如果已指定 --key-store)。

  • –timeout-sec timeout

  • 指定抓取的超时(以秒为单位)。如果未指定,抓取会在 60 秒后停止。