简介
Monkey是一种 command-line 工具, 您可以在任何模拟器或设备上运行它。它将用户事件的伪随机流发送到系统中, 作为对您正在开发的应用程序软件的压力测试。
Monkey包括许多选项, 但它们分成四主要类别:基本配置选项, 如设置要尝试的事件数。
操作限制, 例如将测试限制为单个包。
事件类型和频率。
调试选项
当Monkey运行时, 它生成事件并将它们发送到系统。它也观察系统在被测试的情况下和寻找三条件, 它特别对待:如果您限制了Monkey在一个或多个特定的包中运行, 它会监视尝试导航到任何其他包, 并阻止它们。
如果您的应用程序崩溃或收到任何类型的未经处理的异常, Monkey将停止并报告错误。
如果应用程序生成的应用程序没有响应错误, Monkey将停止并报告错误。
根据您选择的详细级别, 您还将看到有关Monkey的进度和正在生成的事件的报告。存放路径 Monkey程序是Android系统自带的,由Java语言写成,在Android文件系统中的存放路径是: /system/framework/monkey.jar。
大致操作流程 通过名为“monkey”的Shell脚本去启动Monkey.jar程序(shell脚本在Android文件系统中 的存放路径是:/system/bin/monkey),在你指定的APP应用上模拟用户点击,滑动,输入等操作以极快的速度来对设备程序进行压力测试,检测程序是否会发生异常,然后通过日志进行排错。
主要目的测试app 是否会是否会Crash。
基本格式
您可以从命令行或脚本启动Monkey。因为Monkey在模拟器/设备环境中运行, 所以您必须从该环境中的 shell 启动它。您可以'adb shell'开头 来执行此命令, 或者直接进入 shell 并输入Monkey命令。
基本语法是:$ adb shell monkey [选项]
在没有指定选项的情况下, monkey将以安静 (详细) 模式启动, 并将事件发送到您的目标上安装的任何 (和所有) 软件包。下面是一个更典型的命令行, 它将启动应用程序并向其发送500伪随机事件:$ adb shell monkey -p com.android.browser -v 500
参数CategoryOptionDescriptionGeneral–help打印简单的用途向导
-v命令行中的每个 v 都将增加详细级别。级别 0 (默认值) 除了启动通知、测试完成和最终结果外, 没有提供任何信息。1级在运行时提供了有关测试的更多详细信息, 如向活动发送的单个事件。级别2提供了更详细的设置信息, 如选择的或未选择用于测试的活动。
Events-s 伪随机数发生器的种子值。如果您重新运行具有相同种子值的monkey, 它将生成相同的事件序列。
–throttle 在事件之间插入固定的延迟。你可以使用这个选项来减慢monkey的速度。如果未指定, 则不存在延迟, 并且会尽可能快地生成事件。
–pct-touch 调整触摸事件的百分比。(触摸事件是屏幕上单个位置的 down-up 事件。
–pct-motion 调整运动事件的百分比。(运动事件由屏幕上某处的向下事件、一系列伪随机运动和向上事件组成。
–pct-trackball 调整轨迹球事件的百分比。(轨迹球事件由一个或多个随机动作组成, 有时后跟单击
–pct-nav 调整 “基本” 导航事件的百分比。(导航事件由上/下/左/右, 作为来自定向输入设备的输入。
–pct-majornav 调整 “主要” 导航事件的百分比。(这些导航事件通常会导致用户界面中的操作, 如5-way pad 中心按钮、后退键或菜单键。
–pct-syskeys 调整 “系统” 关键事件的百分比。(这些密钥通常保留供系统使用, 如 “主页”、“后退”、“开始呼叫”、“结束呼叫” 或 “音量控制”。
–pct-appswitch 调整活动启动的百分比。在随机的时间间隔, monkey将发出一个 startActivity () 调用, 作为一种方法, 最大限度地覆盖所有活动在您的包。
–pct-anyevent 调整其他类型事件的百分比。这是所有其他类型的事件 (如按键、设备上其他较少使用的按钮等等) 的全部捕获。
Constraints-p 如果您以这种方式指定一个或多个包, monkey将只允许系统访问这些包中的活动。如果您的应用程序需要访问其他包中的活动 (例如, 选择联系人), 您还需要指定这些包。如果您不指定任何软件包, monkey将允许系统在所有包中启动活动。要指定多个包, 请使用-p 选项多次-每包一-p 选项。
-c 如果您以这种方式指定一个或多个类别, 则monkey将只允许系统访问与指定类别之一一起列出的活动。如果您不指定任何类别, monkey将选择与类别意向列出的活动. CATEGORY_LAUNCHER 或意图. CATEGORY_MONKEY要指定多个类别, 请使用-c 选项多次-每类别一-c 选项。
Debugging–dbg-no-events如果指定, monkey将执行初始登录到到一个测试活动, 但不会产生任何进一步的事件。为了得到最好的结果, 结合-v, 一个或多个包约束, 和一个非零 –throttle, 以保持monkey运行超过30秒。这提供了一个环境, 您可以在其中监视应用程序调用的包转换。
–hprof如果设置, 此选项将在monkey事件序列前后立即生成分析报告。这将产生大 (〜 5 mb) 文件的数据, 所以使用谨慎。有关跟踪文件的详细信息, 请参阅 Traceview。
–ignore-crashes通常情况下, 当应用程序崩溃或遇到任何类型的未经处理的异常时, monkey就会停止。如果指定此选项, 则monkey将继续向系统发送事件, 直到计数完成。
–ignore-timeouts通常情况下, 当应用程序遇到任何类型的超时错误 (如 “应用程序未响应” 对话框) 时, 该monkey就会停止。如果指定此选项, 则monkey将继续向系统发送事件, 直到计数完成。
–ignore-security-exceptions通常情况下, 当应用程序遇到任何类型的权限错误时, 例如, 如果它尝试启动需要某些权限的活动, 则该monkey将停止。如果指定此选项, 则monkey将继续向系统发送事件, 直到计数完成。
--ignore-native-crashes当应用底层发生c/c++崩溃时,monkey就会停止。如果指定此选项, 则monkey将继续向系统发送事件, 直到计数完成
–kill-process-after-error通常情况下, 当monkey由于错误而停止时, 失败的应用程序将被保留运行。设置此选项后, 系统将发出信号, 以停止发生错误的进程。注意, 在正常 (成功) 完成后, 启动的进程 (es) 不会停止, 并且该设备仅在最后一个事件之后的最后一个状态中保留。
–monitor-native-crashes监视和报告在 Android 系统本机代码中发生的崩溃。如果设置了-kill-process-after-error, 系统将停止。
例子
1) 常用的例子:adb shell monkey -p com.vlife.stage -s 500 --throttle 100 --ignore-crashes --ignore-timeouts --monitor-native-crashes -v -v 10000
产生时间序列的种子值:500,事件间延迟 100 忽略程序崩溃 、 忽略超时 、 监视本地程序崩溃 、 详细信息级别为2 , 产生 10000个事件
2)adb shell monkey -p com.vlife.stage --throttle 100 --ignore-crashes --ignore-timeouts --kill-process-after-error
--pct-touch 35
--pct-syskeys 30
--pct-appswitch 35 --hprof -v -v -v 50000:
注意:这个命令定义了事件的百分比,但并没有定义种子值,在实际应用中是非常不推荐的,只有同样的种子值才会产生同样的序列,为了方便重现问题一定要加-s,
另外日志的级别建议选择详细级别,三个-v -v -v
日志导出
例如:保存到电脑上并命名为monkey.txt
adb shell monkey -p 包名 -v 1000 > E:/monkey.txt
例如:保存到电脑上标准流与错误流分开保存,分别命名为info.txt,error.txt
adb shell monkey -p 包名 -v 1000 1>E:/info.txt 2>E:/error.txt
快速从monkey.txt日志中看问题
测试结果初步判断monkey执行时未加--ignore-crashes参数,就先浏览日志中Events injected: 值,查看当前已执行的次数,就知道有无bug
程序无响应的问题:在日志中搜索 “ANR”
崩溃问题:在日志中搜索 “Exception” ,在这里顺便提一下常见的Java异常:算术异常类:ArithmeticExecption
空指针异常类:NullPointerException
类型强制转换异常:ClassCastException
数组负下标异常:NegativeArrayException
数组下标越界异常:ArrayIndexOutOfBoundsException
违背安全原则异常:SecturityException
文件已结束异常:EOFException
文件未找到异常:FileNotFoundException
字符串转换为数字异常:NumberFormatException
操作数据库异常:SQLException
输入输出异常:IOException
违法访问错误:IllegalAccessError
内存不足错误:OutOfMemoryError
找出问题后的操作步骤:找到是monkey里面的哪个地方出错
查看Monkey里面出错前的一些事件动作,并手动执行该动作
若以上步骤还不能找出,可以使用之前执行的monkey命令再执行一遍,注意seed值要一样。
Monkey日志讲解
伪随机种子数与事件总数Monkey: seed=100 count=10000
允许测试包AllowPackage: com.yulore.yellowpage
Category包含的LAUNCHERIncludeCategory: android.intent.category.LAUNCHER
Category包含的MONKEYIncludeCategory: android.intent.category.MONK
查询允许包的activity 结果列表// Selecting main activities from category android.intent.category.LAUNCHER
这些都不是指定包的activity// - NOT USING main activity com.android.calendar.AllInOneActivity (from package com.android.calendar)
// - NOT USING main activity com.android.camera.CameraLauncher (from package com.android.camera2)
// - NOT USING main activity com.android.contacts.activities.PeopleActivity (from package com.android.contacts)
从这也可以看出你手机上都安装了哪些应用,下面就是我们指定的包的activity// + Using main activity com.yulore.yellowpage.activity.SplashActivity (from package com.yulore.yellowpage)
// Selecting main activities from category android.intent.category.MONKEY
种子为100// Seeded: 100
事件百分比// Event percentages:
// 0: 15.0%
// 1: 10.0%
// 2: 2.0%
// 3: 15.0%
// 4: -0.0%
// 5: -0.0%
// 6: 25.0%
// 7: 15.0%
// 8: 2.0%
// 9: 2.0%
// 10: 1.0%
// 11: 13.0%
查看log中第一个Switch,主要是查看 Monkey 执行的是那一个 Activity,譬如下面的 log 中,执行的是com.yulore.yellowpage/.activity.SplashActivity,
在下一个swtich之间的,如果出现了崩溃或其他异常,可以在该Activity中查找问题的所在。
:Switch: #Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.yulore.yellowpage/.activity.SplashActivity;end
// Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.yulore.yellowpage/.activity.SplashActivity } in package com.yulore.yellowpage
sleeping for 0 milliseconds这句 log 是执行Monkey测试时,throttle设定的间隔时间,每出现一次,就代表一个事件。(这个事件是指从用户角度来说的一个事件,
比如点击:实际包括手指按下与抬起两个动作,monkey日记将被记为2个事件)Sleeping for 0 milliseconds
:Sending Key (ACTION_DOWN): 82 // KEYCODE_MENU
:Sending Key (ACTION_UP): 82 // KEYCODE_MENU
Sleeping for 0 milliseconds
:Sending Key (ACTION_DOWN): 23 // KEYCODE_DPAD_CENTER
:Sending Key (ACTION_UP): 23 // KEYCODE_DPAD_CENTER
Sleeping for 0 milliseconds
如果 Monkey 测试顺利执行完成,在 log 的最后,会打印出当前执行事件的次数和所花费的时间Monkey finished代表执行完成。Monkey 执行完成的 log 具体如下:Events injected: 100
:Sending rotation degree=0, persist=false
:Dropped: keys=0 pointers=0 trackballs=0 flips=0 rotations=0
## Network stats: elapsed time=2042ms (0ms mobile, 0ms wifi, 2042ms not connected)
// Monkey finished
Monkey 执行中断,在 log 的最后也能查看到当前大约已执行的次数:Sending Trackball (ACTION_MOVE): 0:(-3.0,1.0)
:Sending Trackball (ACTION_MOVE): 0:(4.0,0.0)
//[calendar_time:2018-04-02 11:23:50.322 system_uptime:718998]
// Sending event #7500
:Sending Trackball (ACTION_MOVE): 0:(3.0,-2.0)
异常结果crashSleeping for 0 milliseconds
:Sending Touch (ACTION_DOWN): 0:(796.0,301.0)
// CRASH: com.lenovo.leos.appstore (pid 27964)
// Short Msg: java.lang.RuntimeException
// Long Msg: java.lang.RuntimeException: Only one Looper may be created per thread
// Build Label: vivo/PD1616/PD1616:7.1.2/N2G47H/compil02262218:user/release-keys
// Build Changelist: eng.compil.20180226.221830
// Build Time: 1519654710000
:Sending Touch (ACTION_UP): 0:(793.6982,299.82098)// java.lang.RuntimeException: Only one Looper may be created per thread
// at android.os.Looper.prepare(Looper.java:89)
// at android.os.Looper.prepare(Looper.java:84)
// at android.os.HandlerThread.run(HandlerThread.java:54)
//
Sleeping for 0 milliseconds
(无需 Root) 基于 Android Monkey 二次开发,实现高速点击的 Android Monkey
MonkeyScript
MonkeyScript 是官方提供的,除了像monkey一样随机乱点之外,还可以通过编写脚本的形式,完成一系列固定的操作。MS 提供一整套完善的API来进行支持,
主要还是基于坐标点的操作,包含常用的:点击、长按、输入、等待等操作。
MonkeyScript虽然需要编写测试脚本,但是实际上它还是属于 Monkey 命令的一部分,需要通过 Monkey 命令进行启动、运行。adb shell monkey -f
可以看到,通过 -f 参数即可用于指定一个 MonkeyScript 脚本进行执行。
需要注意的是,因为 adb shell 的运行环境是在待测试的 Android 设备上,所以需要将MonkeyScript 脚本 pull 到待测试的设备上,然后再进行运行。
下有一段注释规定了monkey script的基本规则,如下monkey event queue. It takes a script. to produce eventssample script. format:
type= raw events
count= 10
speed= 1.0
start data >>
captureDispatchPointer(5109520,5109520,0,230.75429,458.1814,0.20784314,
0.06666667,0,0.0,0.0,65539,0)
captureDispatchKey(5113146,5113146,0,20,0,0,0,0)
captureDispatchFlip(true)type指明类型
count说明执行次数,但是这里改成任何值都执行一次,monkey命令可以指定执行次数,这里也就无所谓了
speed命令执行速率。改动无影响,可以通过monkey命令行指定。
以上三个参数改动都没什么影响,一般不做改动。
start data »相当于一个入口,说明脚本从下面开始执行
MonkeyScript常用API
MonkeyScript 其实提供了非常完备的API,具体细节请看源代码
1)点击事件(DispatchPointer) DispatchPointer 命令用于向一个指定的坐标位置,发送单个手势消息,一般用它来模拟点击的操作。
DispatchPointer ( downTime , eventTime , action , x , y , pressure , size , metaState , xPrecision , yPrecision , device , edgeFlags)
其实这么多参数,只需要关注action 、 x 、y 三个参数即可。
action :事件是按下还是抬起,0 表示按下,1 表示抬起。x、y:表示当前事件触发的X轴和Y轴的坐标。也就是说,两个 DispatchPointer 命令加在一起,分别表示 按下 和 抬起 ,这表示一次点击操作,其余的参数,统一设置为 0 即可。
2)按键消息(DispatchKey)
DispatchKey 主要是用于发送一些 Android 标准的 EventKey 按键消息。但是需要写对应的值。
DispatchKey 消息的方法前面和 DispatchPointer 一样,所以同样也只需要关注 action、x、y 三个参数即可。
3)普通列表项目开启关闭软键盘(DispatchFlip)
DispatchFlip 命令用于打开或者关闭软键盘。DispatchFlip (keyboardOpen)
其中的参数,true 表示打开,false 表示关闭。
4)打开指定的Activity(LaunchActivity) LaunchActivity 命令用于打开任意应用的一个页面,但是前提条件是打开的Activity 需要属性 android:exported 被设定为true,才可以通过 LaunchActivity 打开。
LaunchActivity ( pkg_name , act_name )它的两个参数,分别表示打开的 App 的包名和打开的 Activity 的名称。
5)等待(UserWait) UserWait 命令用于让脚本中断执行一段时间。因为是脚本执行,多个事件之间执行的速度会非常的快,有时候我们需要等待一些事件触发之后的结果返回,需要等待一段时间之后,再继续执行脚本,这个时候就可以使用 UserWait 。
UserWait ( sleepTime )sleepTime 的单位是毫秒。
6) 输入字符串(DispatchString) DispatchString 命令用于向 Shell 输入一个字符串。
DispatchString( input )
input 就是一个字符串即可,但是 MS 对中文的支持并不好,所以尽量输入英文的测试数据。
7)运行 Shell 命令(RunCmd)
RunCmd 命令用于在设备上运行 shell 命令。当然这些 shell 命令必须是当前待测试设备支持的 shell 命令。
RunCmd ( cmd )
参数 cmd 就是需要执行的 shell 命令。
8)键盘事件(DispatchPress)
DispatchPress 命令用于模拟敲击键盘的事件。
DispatchPress( keyName )