monkey通常用于对app进行压力测试,通过monkey工具在模拟器或设备中产生类似用户点击、触摸、手势等一些系统级的伪随机事件流以测试app的稳定性,这好比一只猴子随意操作设备。
一、monkey原理
monkey是一个用java编写的脚本,设备中存放在system/bin/monkey,源码位于development/cmds/monkey/monkey
monkey测试的架构如下:
monkey测试的运行原理如下:
- 解析用户输入的monkey命令:解析出命令中的附加选项,如包名、是否忽略crash、动作间隔等。
- 确定运行范围:根据包名列表提取出monkey测试可唤醒或切换的activity,不在该列表中的应用/组件会被阻止唤醒。
- 确定生成事件的方式:有脚本、网页、随机三种事件生成方式
- -f scriptfile 表示使用脚本方式生成事件。
- -port socketPort 表示从网络端读取事件。
- 否则则为随机生成事件,生成随机事件前先随机打开一个activity。
- 循环执行monkey测试:根据用户命令行输入的执行次数,循环生成事件并执行。
- 上报结果: monkey在运行过程中遇到crash或ANR会停止运行并上报结果。monkey测试优缺点:
优点 | 缺点 |
1、简单易用 | 1、由于操作随机,遍历界面有限,测试有效性不足 |
2、 随机,能覆盖测试用例复杂性 | 2、无法得知bug复现步骤 |
3、路径回环,由于随机性容易陷入特定界面无法退出 |
二、命令介绍
使用monkey -help查看命令详情
$ monkey -help
bash arg: -help
args: [-help]
arg: "-help"
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]
[--match-description TEXT]
[--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] [--pct-pinchzoom PERCENT]
[--pct-permission 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]
[--profile-wait MILLISEC]
[--device-sleep-time MILLISEC]
[--randomize-script]
[--script-log]
[--bugreport]
[--periodic-bugreport]
[--permission-target-system]
COUNT
2.1、基础参数
- -v:用于指定反馈信息详细程度,共三个级别
- Level 0: -v 提供很少的信息,除了启动通知,测试完成和最终结果。
- Level 1: -v -v 提供更详细的信息,如个别事件被发生至测试Activity。
- Level 2:-v -v -v提供更详细的设置等信息,如Activity选中和未选中的测试信息。
adb shell monkey -v 500//随机模式执行500次随机事件,打印信息级别为Level 0
- -s:伪随机数生成器种子值,如果用相同的种子值,则将生成相同的事件序列,该值对于BUG复现至关重要。
adb shell monkey -s 6666 -v 500
- --throttle:事件延时时间
adb shell monkey --throttle 1000 -v 500//随机执行500个事件,事件间隔1秒
- -p:用于指定运行monkey启动的包名,可指定多个包名;如果不指定则系统中所有app都运行启动
adb shell monkey -p XXX -p xxx -v 500
2.2、发送事件类型
- --pct-touch:touch事件由一个DOWN和一个UP事件组成,一组为一个touch事件。
- --pct-motion:motion事件是由屏幕上某处一个down事件、一系列伪随机的移动事件和一个up事件组成。
- --pct-trackball:滚动球事件由一个或多个随机的移动事件(可以是曲线移动)组成,有时会伴随着点击事件。
- --pct-nav:导航事件由方向输入设备的上下左右按键所触发的事件组成,即四个方向键。
- --pct-syskeys:这些按键通常由系统保留使用,如Home、Back、Start Call、End Call、音量调节。
- --pct-anyevent:包含所有其他事件,如按键、其他在设备上不常用的按钮等。
adb shell monkey --throttle 1000 --pct-touch 30 --pct-motion 25 --pct-syskeys 15 -v 500
随机执行500条事件,其中30%触摸事件,25%移动事件,15%系统案件事件,30%其他随机事件。注意:各类事件类型总和不能超过100%。
2.3、调试选项
- --hprof:用于在发送事件序列前后生成性能分析报告,通常会生成在“data/misc”目录
- --ignore-crashes:忽略crash异常,测试过程中发生crash继续执行测试,直到执行完指定事件数,如果不忽略则系统发生crash,monkey测试会停止。
- --ignore-timeouts:忽略超时异常,测试过程中发生ANR继续执行测试,直到执行完指定事件数,如果不忽略则系统发生ANR,moneky测试会停止。
- --ignore-security-exceptions:忽略应用权限异常,测试过程中发生应用权限错误时继续执行测试,直到执行完指定事件数,如果忽略则系统发生应用权限错误,monkey测试会停止。
- --kill-process-after-error:通常,当Monkey由于一个错误而停止时,出错的应用程序将继续处于运行状态。当设置了此选项时,将会通知系统停止发生错误的进程。注意,正常的(成功的)结束,并没有停止启动的进程,设备只是在结束事件之后,简单地保持在最后的状态。
- -monitor-native-crashes:监视并报告Android系统中本地代码的崩溃事件。如果设置了--kill- process-after-error,系统将停止运行。
adb shell monkey --ignore-crashes --ignore-timeouts --ignore-security-exceptions --monitor-native-crashes --throttle 1000 -v 500
三、monkey示例
随机对系统中的应用间隔500ms执行720000次事件,启用Level 2级打印,并将打印重定向指定路径。
adb shell time monkey --throttle 500 -v -v -v 720000 > C:\Users\xxx\Desktop\adbLog\072103.log
四、log分析
上述monkey示例运行结果如下:
adb shell time monkey --throttle 500 -v -v -v 720000 > C:\Users\gd08575\Desktop\adbLog\072103.log
args: [--throttle, 500, -v, -v, -v, 720000]
arg: "--throttle"
arg: "500"
arg: "-v"
arg: "-v"
arg: "-v"
arg: "720000"
arg="--throttle" mCurArgData="null" mNextArg=1 argwas="--throttle" nextarg="500"
data="500"
PS C:\Windows\system32> adb reboot
PS C:\Windows\system32> adb shell time monkey --throttle 500 -v -v -v 720000 > C:\Users\gd08575\Desktop\adbLog\072104.log
args: [--throttle, 500, -v, -v, -v, 720000]
arg: "--throttle"
arg: "500"
arg: "-v"
arg: "-v"
arg: "-v"
arg: "720000"
arg="--throttle" mCurArgData="null" mNextArg=1 argwas="--throttle" nextarg="500"
data="500"
// CRASH: org.codeaurora.gallery (pid 4043)
// Short Msg: java.lang.NullPointerException
// Long Msg: java.lang.NullPointerException: uri
// Build Label: qti/xxx/xxx:10/QKQ1.210910.001/8970_A10_DS:userdebug/dev-keys
// Build Changelist: 8970_A10_DS
// Build Time: 1658127765000
// java.lang.NullPointerException: uri
// at com.android.internal.util.Preconditions.checkNotNull(Preconditions.java:133)
// at android.content.ContentResolver.update(ContentResolver.java:1982)
// at com.android.gallery3d.filtershow.tools.SaveImage.updateFile(SaveImage.java:796)
// at com.android.gallery3d.filtershow.tools.SaveImage.processAndSaveImage(SaveImage.java:526)
// at com.android.gallery3d.filtershow.pipeline.ImageSavingTask.doInBackground(ImageSavingTask.java:124)
// at com.android.gallery3d.filtershow.pipeline.ProcessingTask.processRequest(ProcessingTask.java:61)
// at com.android.gallery3d.filtershow.pipeline.ProcessingTaskController.handleMessage(ProcessingTaskController.java:59)
// at android.os.Handler.dispatchMessage(Handler.java:103)
// at android.os.Looper.loop(Looper.java:214)
// at android.os.HandlerThread.run(HandlerThread.java:67)
//
** System appears to have crashed at event 74163 of 720000 using seed 1658296072289
153m38.49s real 1m34.00s user 0m45.90s system
在运行近2.5h时抛出NPE异常,停止monkey测试,上述log给出了基本报错代码位置,便于定位问题,具体NPE分析过程这里不多赘述。
通常在log中查找error,ANR,crash等报错关键字。
接下来分析生成的log文件:
bash arg: --throttle
bash arg: 500
bash arg: -v
bash arg: -v
bash arg: -v
bash arg: 720000
:Monkey: seed=1658296072289 count=720000
//monkey命令中设置的参数,以及随机生成的种子,通过设置该种子数可用于复现和验证修改措施。
:IncludeCategory: android.intent.category.LAUNCHER
:IncludeCategory: android.intent.category.MONKEY
// Selecting main activities from category android.intent.category.LAUNCHER
// + Using main activity com.android.calendar.AllInOneActivity (from package com.android.calendar)
// + Using main activity com.android.contacts.activities.PeopleActivity (from package com.android.contacts)
// + Using main activity com.android.deskclock.DeskClock (from package com.android.deskclock)
// + Using main activity com.android.email.activity.Welcome (from package com.android.email)
// + Using main activity com.android.mms.ui.ConversationList (from package com.android.mms)
// + Using main activity com.android.music.MusicBrowserActivity (from package com.android.music)
// + Using main activity com.android.music.VideoBrowserActivity (from package com.android.music)
// + Using main activity com.android.settings.Settings (from package com.android.settings)
// + Using main activity com.android.soundrecorder.SoundRecorder (from package com.android.soundrecorder)
// + Using main activity com.android.dialer.main.impl.MainActivity (from package org.codeaurora.dialer)
// + Using main activity com.android.gallery3d.app.GalleryActivity (from package org.codeaurora.gallery)
// + Using main activity com.android.camera.CameraLauncher (from package org.codeaurora.snapcam)
// + Using main activity com.android.documentsui.LauncherActivity (from package com.android.documentsui)
// + Using main activity com.android.quicksearchbox.SearchActivity (from package com.android.quicksearchbox)
// Selecting main activities from category android.intent.category.MONKEY
// + Using main activity com.android.launcher3.Launcher (from package com.android.launcher3)
// + Using main activity com.android.settings.Settings$RunningServicesActivity (from package com.android.settings)
// + Using main activity com.android.settings.Settings$StorageUseActivity (from package com.android.settings)
// Seeded: 1658296072289
//各类调试选项百分比,其中序号所代表的类型定义在
//development/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
public static final int FACTOR_TOUCH = 0;
public static final int FACTOR_MOTION = 1;
public static final int FACTOR_PINCHZOOM = 2;
public static final int FACTOR_TRACKBALL = 3;
public static final int FACTOR_ROTATION = 4;
public static final int FACTOR_PERMISSION = 5;
public static final int FACTOR_NAV = 6;
public static final int FACTOR_MAJORNAV = 7;
public static final int FACTOR_SYSOPS = 8;
public static final int FACTOR_APPSWITCH = 9;
public static final int FACTOR_FLIP = 10;
public static final int FACTOR_ANYTHING = 11;
public static final int FACTORZ_COUNT = 12; // should be last+1
// 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%
//应用切换
:Switch: #Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity;end
// Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity } in package org.codeaurora.gallery
//事件延时及随机事件序列
Sleeping for 500 milliseconds
:Sending Key (ACTION_DOWN): 19 // KEYCODE_DPAD_UP
:Sending Key (ACTION_UP): 19 // KEYCODE_DPAD_UP
Sleeping for 500 milliseconds
:Sending Key (ACTION_DOWN): 167 // KEYCODE_CHANNEL_DOWN
:Sending Key (ACTION_UP): 167 // KEYCODE_CHANNEL_DOWN
Sleeping for 500 milliseconds
:Sending Key (ACTION_DOWN): 33 // KEYCODE_E
:Sending Key (ACTION_UP): 33 // KEYCODE_E
...
五、总结
本文介绍了monkey测试用途,架构以及运行原理和基本命令参数及其作用。结合命令示例和log介绍常用的分析方法。