Monkey使用案例
一、前言
● Monkey是Android SDK提供的一个命令行工具,可以简单方便的发送伪随机的用户事件流,对Android APP做稳定性(压力)测试。
● 我们主要是为了测试app是否存在无响应和崩溃闪退等异常情况。
● 获取测试日志的ANR、CRASH、Exception信息,提供给开发人员分析和定位问题。
● 一般一次Monkey测试0 ANR 、0 CRASH是测试标准。
● 所有提交的应用,都需要经过应用商店的稳定性测试(如小米应用商店)——非功能性测试,即Monkey测试和遍历性测试。
二、基本操作流
● 安装adb,安卓手机开启USB调试,并成功连接设备
● 执行monkey测试命令,获取测试日志
● 查找ANR、CRASH、Exception信息,定位问题
● 开发修复问题后,用相同seed值测试确保问题修复
1、ADB搭建
此处只列举主要步骤
1.1、下载ADB命令行工具adb kit
下载地址: https://adbshell.com/downloads
得到adb.zip(仅含三个文件:adb.exe
、AdbWinApi.dll
、AdbWinUsbApi.dll
),将该三个文件直接拷贝至C:\Windows\System32
和C:\Windows\SysWOW64
## 以下即为完成
adb --version
Android Debug Bridge version 1.0.41
Version 29.0.5-5949299
Installed as C:\Windows\system32\adb.exe
1.2、下载ADB驱动ADB Driver Installer
当android手机连接通过USB连接电脑时,经常碰到找不到驱动,无法识别设备。通常遇到这种情况我们需要下载相应的驱动安装包,安装驱动。
安装方法:
● 手机或android设备连接至电脑(本机模拟器需要:adb connect 127.0.0.1:62001)
● 双击ADBDriverInstaller.exe
● 界面将显示未安装ABD驱动的设备名
● 点击install完成安装
2、完整测试命令分析
可通过adb shell monkey -help
查看使用参数
2.1 完整测试命令
主要使用命令:
参考小米开放平台的monkey参数:https://dev.mi.com/console/doc/detail?pId=43
# 根据小米开放平台测试参数修改而来的,实际使用中的测试参数
adb shell monkey -p com.xxx.consumer --pct-touch 40 --pct-motion 25 --pct-nav 5 --pct-majornav 15 --pct-appswitch 5 --pct-anyevent 5 --pct-trackball 0 --pct-syskeys 0 -s 123456 --throttle 300 --ignore-crashes --ignore-timeouts -v -v 1000 1>D:\Monkeytest\xxxAppMonkeyReport.txt 2>D:\Monkeytest\xxxAppMonkeyErrorReport.txt
# 小米开放平台的测试参数
adb shell monkey -v --throttle 300 --pct-touch 30 --pct-motion 20 --pct-nav 20 --pct-majornav 15 --pct-appswitch 5 --pct-anyevent 5 --pct-trackball 0 --pct-syskeys 0 -p '%s' 1000
# 中断测试
# shell 9173 3896 4466296 110492 futex_wait_queue_me 0 S com.android.commands.monkey
adb shell ps | find "monkey"
adb shell kill "9173"
如果存在多个devices,指定一个设备如adb -s 2390d880 shell
再执行monkey命令
2.2 指定测试App包名,-p参数
● 使用-p参数来制定测试应用的包名(Package)
● 获取手机端当前打开App的信息(如获取包名类名)adb shell dumpsys window |findstr mCurrent。如包名:com.xxx.consumer
# 获取命令:获取手机端当前打开App的信息
adb shell dumpsys window |findstr mCurrent
# 其中包名/类名 com.xxx.consumer/com.xxx.consumer.ui.activity.TabMainAct
mCurrentUserId=0
mCurrentUserId=0
mCurrentFocus=Window{e41c87f mode=1 rootTaskId=2322 u0 com.xxx.consumer/com.xxx.consumer.ui.activity.TabMainAct}
mCurrent=[0,137][1440,3200]
mCurrentAppOrientation=SCREEN_ORIENTATION_PORTRAIT
mCurrentRotation=ROTATION_0
2.3、限制Monkey执行的事件类型和占比,–pct-xxx参数
事件名称 | 事件参数 | 事件说明 |
---|---|---|
触摸事件 | --pct-touch | 是指在屏幕某处按下并抬起的操作类似于点击操作,由一组Touch(ACTION_DOWN)和Touch(ACTION_UP)事件组成。 |
手势事件 | --pct-motion | 是指在屏幕某处的直线滑动操作,由一个ACTION_DOWN事件、一系列ACTION_MOVE事件和一个ACTION_UP事件组成 |
轨迹球事件 | --pct-trackball | 模拟轨迹球的操作,现在的手机几乎都没有轨迹球 |
缩放事件 | --pct-pinchzoom | 指放大缩小手势操作 |
屏幕旋转事件 | --pct-rotation | 模拟的Android手机的横屏和竖屏切换,是一个隐藏事件 |
基本导航事件 | --pct-nav | 是指点击方向输入设备的上、下、左、右按键的操作,现在手机上很少有上、下、左、右按键,这种事件一般用得比较少。 |
主要导航事件 | --pct-majornav | 点击“主要导航”按键的操作,这些按键通常会导致UI界面中的动作,如键盘的中间键、回退按键、菜单按键 |
系统事件 | --pct-syskeys | 点击系统使用的按键的操作,如点击Home键、返回键、音量调节键 |
启动事件 | --pct-appswitch | 在手机上启动一个Activity的操作,日志中开头:Switch: #Intent; action=android.intent.action.MAIN; |
键盘事件 | --pct-flip | 键盘事件主要是一些与键盘相关的操作。比如点击输入框、键盘弹起、点击输入框以外区域、键盘收回等 |
其他类型事件 | --pct-anyevent | 其他类型事件包括了除前面提到的10种事件外其他所有的事件 |
2.4、指定命令执行的seed值,-s参数
Monkey会根据seed值来生成对应事件流,同一个seed生成的事件流是完全相同的。指定了seed值,可以在测试发现问题时,方便进行问题复现,相同的seed值,两次Monkey测试所产生的事件序列也相同的。不指定的话会自动分配。
2.5、控制Monkey每个操作之间的时间间隔,–throttle参数
--throttle 400
指定操作之间的时间间隔,单位是ms,可根据实际需求修改。
● 更接近用户实际的使用操作场景,正常用户操作都会有一定的时间间隔;
● 不希望因为过于频繁的操作而导致系统崩溃,在一些配置比较低的手机上执行测试时。因此通过–throttle设置Monkey每个操作固定延迟0.4秒。
2.6、Monkey遇到异常时能继续执行,–ignore-crash和–ignore-timeouts参数
在执行Monkey测试时,会因为应用的崩溃或没有响应而意外终止,可以在命令中增加限制参数–ignore-crash和–ignore-timeouts,使得Monkey在遇到崩溃或没有响应的时候,能在日志中记录相关信息,并继续执行后续的测试。
2.7、指定log的详细级别,-v参数
Monkey的日志输出分为3个级别(-v之间需要空格分开):
● Level 0(缺省值):除启动提示、测试完成和最终结果之外,提供较少信息。
● Level 1(-v -v):提供较为详细的测试信息,如逐个发送到Activity的事件。
● Level 2(-v -v -v):提供更加详细的设置信息,如测试中被选中的或未被选中的Activity等。
日志的级别越高,其详细程度也越高。为了方便问题的定位,可以将日志级别设置为level2。
2.8、最后是模拟执行事件次数,和指定生成日志文件目录
5000 > D:\GeelyAppMonkeyTest.log
如设置为模拟事件执行次数为5000,目录为D:\GeelyAppMonkeyTest.log
执行时间:经实际测试事件次数5000,操作间隔时间0.4s的情况下耗时约0.4s*5000=2000s
3、日志分析(关注异常信息)
Monkey运行时输出的日志一般包含四类信息,分别是测试命令信息、伪随机事件流信息、异常信息、Monkey执行结果信息。
3.1、测试命令信息
● 测试命令信息
● 随机种子值,执行事件数量
:Monkey: seed=12358 count=50000
● 可运行的应用列表
:AllowPackage: com.tencent.android.qqdownloader
● Category包含LAUNCHER和MONKEY
:IncludeCategory: android.intent.category.LAUNCHER
:IncludeCategory: android.intent.category.MONKEY
● 各事件的百分比
--pct-touch 70 触摸事件百分比70
--pct-motion 5 手势事件百分比70
--pct-trackball 5 轨迹球事件百分比10
--pct-pinchzoom 2 缩放事件百分比2
--pct-rotation 0 屏幕旋转事件百分比0
--pct-nav 0 基本导航事件百分比0
--pct-majornav 5 主要导航事件百分比5
--pct-syskeys 5 系统事件百分比 5
--pct-appswitch 2 Activity启动事件百分比2
--pct-flip 2 键盘翻转事件百分比
--pct-anyevent 2 其他事件百分比
bash arg: -p
bash arg: com.geely.consumer
bash arg: --pct-touch
bash arg: 40
bash arg: --pct-motion
bash arg: 25
bash arg: --pct-appswitch
bash arg: 10
bash arg: --pct-rotation
bash arg: 5
bash arg: -s
bash arg: 12358
bash arg: --throttle
bash arg: 400
bash arg: --ignore-crashes
bash arg: --ignore-timeouts
bash arg: -vv
bash arg: 50000
:Monkey: seed=12358 count=50000
:AllowPackage: com.geely.consumer
:IncludeCategory: android.intent.category.LAUNCHER
:IncludeCategory: android.intent.category.MONKEY
// Event percentages:
// 0: 40.0%
// 1: 25.0%
// 2: 0.5479452%
// 3: 4.109589%
// 4: 5.0%
// 5: -0.0%
// 6: 6.849315%
// 7: 4.109589%
// 8: 0.5479452%
// 9: 10.0%
// 10: 0.2739726%
// 11: 3.5616438%
3.2、伪随机事件流信息
当Monkey开始执行测试后,会顺序输出执行的事件流信息,如:
#执行的事件流信息
#启动App事件
Switch: #Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.xx.consumer/com.xxx.market.deploy.activity.DevContainActivity;end
// Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.xxx.consumer/com.geely.market.deploy.activity.DevContainActivity } in package com.xxx.consumer
// Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.xxx.consumer/com.geely.market.deploy.activity.DevContainActivity } in package com.xxx.consumer
#点击事件
:Sending Touch (ACTION_DOWN): 0:(308.0,2215.0)
3.3、异常信息查找,日志搜索ANR、CRASH、Exception
当Monkey执行过程中遇到错误时,会输出对应异常信息,关键字查询:应用程序无响应(ANR)
、崩溃(CRASH)
、其他问题(Exception)
、强制退出(force closed)
● ANR:指当Android系统监测到应用程序在5秒内没有响应输入的事件或广播在10秒内没有执行完毕时抛出无响应弹窗提示
● CRASH:应用程序出现错误时导致程序崩溃、异常停止或退出的情况
● Exception:其他问题的一些问题
● 强制退出:在日志中搜索 force closed
当获取到CRASH和ANR日志信息后,理论上开发人员就可以开始根据日志内容分析和定位问题了。
如果标准流和错误流分开保存的话则直接查看错误流文件即可,如:xxxAppMonkeyErrorReport.txt
CRASH的错误日志如下:
// CRASH: com.xxx.consumer (pid 24358)
// Short Msg: kotlin.KotlinNullPointerException
// Long Msg: kotlin.KotlinNullPointerException
// Build Label: Xiaomi/venus/venus:11/RKQ1.200928.002/V12.5.15.0.RKBCNXM:user/release-keys
// Build Changelist: V12.5.15.0.RKBCNXM
// Build Time: 1635085758000
// kotlin.KotlinNullPointerException
// at com.xxx.consumer.circle.ui.fragment.AllCircleFragment$initView$3.onLoadMore(AllCircleFragment.kt:116)
// at com.scwang.smart.refresh.layout.SmartRefreshLayout$5.run(SmartRefreshLayout.java:1727)
// at android.os.Handler.handleCallback(Handler.java:938)
// at android.os.Handler.dispatchMessage(Handler.java:99)
// at android.os.Looper.loop(Looper.java:233)
// at android.app.ActivityThread.main(ActivityThread.java:7892)
// at java.lang.reflect.Method.invoke(Native Method)
// at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
// at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
//
3.4、重现问题
● 找到Monkey哪个部分有问题
● 查看Monkey里面出错前的一些事件动作,并手动执行该动作
● 如果不能重现,执行之前的语句,seed值要相同
三、目前实际使用遇到的问题
1、小米手机跑Monkey调起app后不再继续运行且报错
错误代码:Injecting to another application requires INJECT_EVENTS permission
问题解决方案:
● 小米手机有两个USB调试开关,需要开启USB调试(安全设置)开关,且开启时要求设备安装了SIM卡才能成功开启。
● 设置入口:设置—> 更多设置—> 开发者选项 —>USB调试(安全设置)
2、手机在跑Monkey时无法观察到点击了何处和滑动的轨迹
实现方案:
● 小米手机有两个USB调试开关,需要开启USB调试(安全设置)开关,且开启时要求设备安装了SIM卡才能成功开启。
● 设置入口:设置—> 更多设置—> 开发者选项 —>打开显示点按操作反馈、指针位置开关
3、小米机型出现theme_compatibility.xml报错
猜测可能和系统主题有关,但是此处并非APP的报错,似乎可以忽略该问题
java.io.FileNotFoundException: /data/system/theme_config/theme_compatibility.xml: open failed: ENOENT (No such file or directory)
at libcore.io.IoBridge.open(IoBridge.java:492)
at java.io.FileInputStream.<init>(FileInputStream.java:160)
at java.io.FileInputStream.<init>(FileInputStream.java:115)
at java.io.FileReader.<init>(FileReader.java:58)
at miui.content.res.ThemeCompatibilityLoader.getVersion(ThemeCompatibilityLoader.java:108)
4、实际使用中一直需要连着电脑操作,是否可以不连电脑。
解决方式:通过以下新增可执行的bat文件,pc启动后即可断开usb,日志按照日期建文件夹存到手机上
set folderName=%date:~0,4%%date:~5,2%%date:~8,2%
set fileName=%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%
adb shell mkdir -p /storage/emulated/0/Monkey/log/%folderName%
adb shell "monkey -p com.xxx.consumer --pct-touch 60 --pct-motion 30 --pct-nav 0 --pct-majornav 0 --pct-appswitch 5 --pct-anyevent 5 --pct-trackball 0 --pct-syskeys 0 -s 123456 --throttle 300 --ignore-crashes --ignore-timeouts -v -v 250 1>/storage/emulated/0/Monkey/log/%folderName%/xxxAppMonkeyReport%fileName%.txt 2>/storage/emulated/0/Monkey/log/%folderName%/xxxAppMonkeyErrorReport%fileName%.txt" &
n、完善中待续。。。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。