一, Monkey测试简介
Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等),实现对正在开发的应用程序进行压力测试。Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。
基本语法
$ adb shell monkey [options]
如果不指定options,Monkey将以无反馈模式启动,并把事件任意发送到安装在目标环境中的全部应用程序
$ adb shell monkey -p package -v 500
指定对package这个应用程序进行monkey测试,并向其发送500个伪随机事件。其中 -p 表示对象包包,–v 表示反馈信息级别
命令参数
可以使用命令 adb shell monkey -help 查看命令参数
1、参数: -p
用于约束限制,用此参数指定一个或多个应用。指定应用之后,monkey将只允许系统启动指定的app;如果不指定应用,将允许系统启动设备中的所有应用。
指定一个应用: adb shell monkey -p com.ifeng.news2 100
指定多个应用:adb shell monkey -p com.ifext.news –p com.ifeng.news2 100
不指定应用:adb shell monkey 100
2、参数:-c
用于约束限制,用此参数指定了一个或几个类别,Monkey将只允许系统启动被这些类别中的某个类别列出的Activity。如果不指定任何类别,Monkey将选择下列类别中列出的Activity:Intent.CATEGORY.LAUNCHER 或 Intent.CATEGORY.MONKEY。要指定多个类别,需要使用多个-c选项,每个-c选项只能用于一个类别。
3、参数:-v
用于指定反馈信息级别(信息级别就是日志的详细程度),总共分3个级别:
默认级别 Level 0:-v
adb shell monkey -p com.ifeng.news2 –v 100:说明仅提供启动提示、测试完成和最终结果等少量信息
日志级别 Level 1:-v -v
adb shell monkey -p com.ifeng.news2 –v -v 100:说明提供较为详细的日志,包括每个发送到Activity的事件信息
日志级别 Level 2:-v -v -v
adb shell monkey -p com.ifeng.news2 –v -v –v 100:说明最详细的日志,包括了测试中选中/未选中的Activity信息
4、参数: -s
伪随机数生成器的seed值。如果用相同的seed值再次运行Monkey,它将生成相同的事件序列
Monkey 测试1:adb shell monkey -p com.ifeng.news2 -s 10 100
Monkey 测试2:adb shell monkey -p com.ifeng.news2 –s 10 100
两次测试的效果是相同的,因为模拟的用户操作序列(每次操作按照一定的先后顺序所组成的一系列操作,即一个序列)是一样的。
5、参数: --throttle<毫秒>
用于指定用户操作(即事件)间的延时,单位是毫秒
adb shell monkey -p com.ifeng.news2 --throttle 5000 100
6、参数: --ignore-crashes
用于指定当应用程序崩溃时(Force& Close错误),Monkey是否停止运行。如果使用此参数,即使应用程序崩溃,Monkey依然会发送事件,直到事件计数完成。
adb shellmonkey -p com.ifeng.news2 --ignore-crashes 1000
测试过程中即使程序崩溃,Monkey依然会继续发送事件直到事件数目达到1000为止
adb shellmonkey -p com.ifeng.news2 1000
测试过程中,如果acg程序崩溃,Monkey将会停止运行
7、参数: --ignore-timeouts
用于指定当应用程序发生ANR(Application No Responding)错误时,Monkey是否停止运行。如果使用此参数,即使应用程序发生ANR错误,Monkey依然会发送事件,直到事件计数完成。
adb shellmonkey -p com.ifeng.news2--ignore-timeouts 1000
8、参数: --ignore-security-exceptions
用于指定当应用程序发生许可错误时(如证书许可,网络许可等),Monkey是否停止运行。如果使用此参数,即使应用程序发生许可错误,Monkey依然会发送事件,直到事件计数完成。
adb shellmonkey -p com.ifeng.news2 --ignore-security-exception 1000
9、参数: --kill-process-after-error
用于指定当应用程序发生错误时,是否停止其运行。如果指定此参数,当应用程序发生错误时,应用程序停止运行并保持在当前状态(注意:应用程序仅是静止在发生错误时的状态,系统并不会结束该应用程序的进程)。
adb shellmonkey -p cn.emoney.acg --kill-process-after-error 1000
10、参数: --monitor-native-crashes
用于指定是否监视并报告应用程序发生崩溃的本地代码。
adb shellmonkey -p cn.emoney.acg --monitor-native-crashes 1000
11、参数: --pct-{+事件类别}{+事件类别百分比}
用于指定每种类别事件的数目百分比(在Monkey事件序列中,该类事件数目占总事件数目的百分比)
--pct-touch{+百分比}:
调整触摸事件的百分比(触摸事件是一个down-up事件,它发生在屏幕上的某单一位置)
adb shell monkey -p com.ifeng.news2 --pct-touch 10 1000
--pct-motion {+百分比}:
调整动作事件的百分比(动作事件由屏幕上某处的一个down事件、一系列的伪随件机事和一个up事件组成)
adb shell monkey -p com.ifeng.news2 --pct-motion 20 1000
--pct-trackball {+百分比}:
调整轨迹事件的百分比(轨迹事件由一个或几个随机的移动组成,有时还伴随有点击)
adb shell monkey -p com.ifeng.news2 --pct-trackball 30 1000
--pct-nav {+百分比}:
调整“基本”导航事件的百分比(导航事件由来自方向输入设备的up/down/left/right组成)
adb shell monkey -p com.ifeng.news2 --pct-nav 40 1000
--pct-majornav {+百分比}:
调整“主要”导航事件的百分比(这些导航事件通常引发图形界面中的动作,如:5-way键盘的中间按键、回退按键、菜单按键)
adb shell monkey -p com.ifeng.news2 --pct-majornav 50 1000
二.Monkey日志内容解析
Monkey运行时输出的日志一般包含四类信息,分别是测试命令信息、伪随机事件流信息、异常信息、Monkey执行结果信息。
1)测试命令信息
Monkey启动后会输出当前所执行命令的各种参数信息,其中包括种子(Seed)信息、事件数量、可运行的应用列表以及各事件百分比等。这些信息都是通过Monkey命令参数所指定的,这部分日志信息的解析,如代码清单4-3所示。
代码清单4-3 Monkey日志-测试命令信息
//测试命令信息
//随机种子值,执行事件数量
:Monkey: seed=1454215444564 count=10
//可运行的应用列表
:AllowPackage: com.tencent.android.qqdownloader
//Category包含LAUNCHER和MONKEY
:IncludeCategory: android.intent.category.LAUNCHER
:IncludeCategory: android.intent.category.MONKEY
//各事件的百分比
// Event percentages:
// 0: 15.0% 事件0:--pct-touch
// 1: 10.0% 事件1:--pct-motion
// 2: 2.0% 事件2:--pct-pinchzoom
// 3: 15.0% 事件3:--pct-trackball
// 4: -0.0% 事件4:--pct-rotation
// 5: 25.0% 事件5:--pct-nav
// 6: 15.0% 事件6:--pct-majornav
// 7: 2.0% 事件7:--pct-syskeys
// 8: 2.0% 事件8:--pct-appswitch
// 9: 1.0% 事件9:--pct-flip
// 10: 13.0% 事件10:--pct-anyevent
2)伪随机事件流信息
当Monkey开始执行测试后,会顺序输出执行的事件流信息,主要是前面提到的11大事件。这部分日志信息的解析,如代码清单4-4所示。
代码清单4-4 Monkey日志-伪随机事件流信息
//执行的事件流信息
//启动App事件
:Switch: #Intent; action=android.intent.action.MAIN; category=android.intent.
category.LAUNCHER; launchFlags=0x10200000; component=com.tencent.android.
qqdownloader/com.tencent.assistant.activity.SplashActivity; end
// Allowing start of Intent { act=android.intent.action.MAIN cat=[android.
intent.category.LAUNCHER] cmp=com.tencent.android.qqdownloader/com.tencent.
assistant.activity.SplashActivity } in packagecom.tencent.android.qqdownloader
//轨迹球事件
:Sending Trackball (ACTION_MOVE): 0:(4.0,2.0)
//点击事件
:Sending Touch (ACTION_DOWN): 0:(387.0,1858.0)
:Sending Touch (ACTION_UP): 0:(385.8215,1861.3011)
//延时
Sleeping for 0 milliseconds
…
3)异常信息
当Monkey执行过程中遇到错误时,会输出对应异常信息,如代码清单4-5所示。
代码清单4-5 Monkey日志-异常信息
//发送Crash的应用包名和pid
// CRASH: com.tencent.android.qqdownloader (pid 912)
//Crash的简要信息
// Short Msg: java.lang.ClassNotFoundException
//Crash的详细信息
// Long Msg: java.lang.ClassNotFoundException: Didn't find class "com.
qq.AppService.AstApp" on path DexPathList[[zip file "/data/app/com.tencent.
android.qqdownloader-2.apk"], nativeLibraryDirectories[/data/app-lib/com.
tencent.android.qqdownloader-2, /vendor/lib, /system/lib]]
//机型和系统信息
// Build Label: Xiaomi/pisces/pisces:4.4.4/KTU84P/5.12.24:user/release-keys
// Build Changelist: 5.12.24
// Build Time: 1450958964000
//Crash的详细日志
// java.lang.RuntimeException: Unable to instantiate application com.
qq.AppService.AstApp: java.lan.ClassNotFoundException: Didn't find class "com.
qq.AppService.AstApp" on path: DexPathList[[zip fil "/data/app/com.tencent.
android.qqdownloader-2.apk"], nativeLibraryDirectories=[/data/app-lib/com.
tecent.android.qqdownloader-2, /vendor/lib, /system/lib]]
// at android.app.LoadedApk.makeApplication(LoadedApk.java:509)
// at android.app.ActivityThread.access$1500(ActivityThread.java:138)
// at dalvik.system.NativeStart.main(Native Method)
// ... 11 more
//
4)Monkey执行结果信息
当Monkey执行完所有事件后,会输出执行结果信息,其中包括执行的事件数量、旋转的角度、丢失的事件数量、网络状态以及Monkey最终的执行结果,如代码清单4-6所示。
代码清单4-6 Monkey日志-执行成功结果信息
//执行的事件数量
Events injected: 10
//旋转的角度为0
:Sending rotation degree=0, persist=false
//丢失的事件数量
:Dropped: keys=0 pointers=0 trackballs=0 flips=0 rotations=0
//网络状态,移动网络联网0ms, Wi-Fi联网0ms,没联网144ms
## Network stats: elapsed time=144ms (0ms mobile, 0ms wifi, 144ms not connected)
// Monkey finished
如果Monkey执行过程中出现了异常导致执行失败,会输出对应的执行失败的原因,第几个事件执行失败以及所使用的随机种子数,如代码清单4-7所示。
代码清单4-7 Monkey日志-执行失败结果信息
//显示Monkey执行失败
** Monkey aborted due to error.
//执行的事件数量
Events injected: 8
//旋转的角度为0
:Sending rotation degree=0, persist=false
//丢失的事件数量
:Dropped: keys=0 pointers=0 trackballs=0 flips=0 rotations=0
//网络状态
## Network stats: elapsed time=405ms (0ms mobile, 0ms wifi, 405ms not connected)
//提示在执行到第8个事件时出现Crash,以及所使用的随机种子的值
** System appears to have crashed at event 8 of 100 using seed 1454216848235
3.Monkey日志异常信息查找
Monkey执行过程中常见的错误类型主要有两类:应用程序无响应(ANR)和崩溃(Crash)。
(1)ANR是指当Android系统监测到应用程序在5秒内没有响应输入的事件或广播在10秒内没有执行完毕时抛出无响应提示。当出现ANR时弹出的错误提示框如图4-9所示。ANR弹窗
(2)Crash是指当应用程序出现错误时导致程序异常停止或退出的情况,当出现Crash时通常会弹出对应的错误提示框如图4-10所示。crash弹窗
表4-7 常见Crash信息表
(3)其他问题:在日志中搜索”Exception”和“ERROR"等信息,再具体分析出错的情况及相应的日志输出。
三,Monkey测试如何做才更高大上?
作为测试同学,尤其是测试开发,或是高级测试开发及以上等级的同学,执行一下Monkey测试,再分析一下测试结果,是不是显得有点儿Low呢?完全体现不出我们的设计理念及代码水平嘛!那如何才能将Monkey测试做的高大上呢?
1,前期数据准备
并不是所有的app直接执行一下monkey命令,分析一下测试结果就行;如新浪微博,今日头条这类信息流展示类的app,直接连接电脑,执行Monkey测试没有问题。可是如QQ,金融类的App,打开的时候就要求我们登录,此时如果直接执行Monkey测试,那只能操作到登录界面,后面的业务逻辑相关的页面根本操作不到的。所以为了更好地进行测试,我们需要先登录被测试App,切到测试环境,构造业务相关的数据,如添加QQ好友,发QQ信息等,然后在此基础上执行monkey测试,才会更加真实;而这些操作,可以借助于App自动化测试框架Appium来实现。
2,Money配置化执行
Monkey执行的时候参数非常多,每次输入命令非常不方便。所以我们可以封装Monkey执行参数,将其中需要变化的参数,如执行次数,要测试的App PageName等参数化,根据不同的执行需要,通过参数的形式传递过来即可。而此类问题,可以通过Python,Java,Shell等进行封装,定制化执行即可。当然可以对要测试的App的信息进行智能化分析,自动识别执行,从而使代码更加灵活。
3,测试结果的智能分析
要知道执行的结果,我们需要采取上面的方法分析执行日志;但是如果执行的次数过多,执行的频繁的话,日志分析也是很大的工作量。所以我们可以对日志执行的结果进行智能分析,在执行Monkey测试的时候,把执行手机的型号,系统信息以及其他必要的信息写入日志,然后对过shell命令对日志进行分析。自动过滤与统计出错误信息的数量 ,出错的日志信息等,分别写入错误统计文件或是数据库中,以备后续生成测试报告或是图形化展示执行结果做数据准备。
4,自动生成测试报告
清晰明了的测试报告是提高测试效率的重要手段,如果执行结束后能很快明确执行结果,测试效率必然很高。这就要求我们在执行完monkey测试后,通过对日志的智能分析,自动生成测试报告,测试报告中需要包括这次执行的环境信息,执行结果的汇总信息,以及对出错信息的展示。所以可能借助于Html+Css+js来生成的我们的测试报告,将测试结果的智能分析数据,灵活地展现出来。
通过对上面的四个功能的分析,我们可以对Monkey测试做一个整体设计,设计出合适的代码架构对上面的功能进行整体的封装和数据串联;实现如下流程所示:
经过合适的代码实现,即能完成一个有一定设计理念,具备智能分析能力的Monkey测试项目。后续如果有需求,可以在兼容性,相关业务的关联上进行扩展,从而形成App性能测试平台或是生态。这是我最近在做Monkey测试的一些思考,分享给大家,希望能给你带来点不一样的思考!