4、Monkey测试实战:Monkey工具原理、常用参数、脚本编写与执行
好,咱们进入第四讲。Monkey测试,说白了就是让系统自己跟自己玩,我们在一旁观察它会不会崩溃。很多刚入行的朋友觉得Monkey就是瞎点,其实不然。我做了这么多年座舱测试,Monkey用好了,能挖出不少隐蔽的稳定性问题。
4.1 Monkey工具原理
Monkey是Android系统自带的一个命令行工具。它模拟用户的触摸、滑动、按键等操作,向系统发送伪随机的事件流。你想想看,座舱系统在真实使用中,用户的操作是千奇百怪的。Monkey就是帮我们用一种暴力但有效的方式,去覆盖那些我们手动测试很难想到的边界场景。
它的核心机制很简单:生成随机事件 → 发送给系统 → 观察是否出现ANR或崩溃。但这里有个关键点——Monkey并不关心你的业务逻辑,它只负责“捣乱”。所以,我们用它来测试的是系统的底层稳定性,而不是功能正确性。
核心原理总结:
- 基于伪随机数生成器产生事件序列
- 事件类型包括:触摸、手势、轨迹球、导航、按键、系统按键等
- 通过adb shell向目标设备发送事件流
- 监控系统是否出现未捕获异常或ANR
我个人习惯把Monkey比作一个“熊孩子”。你把它关在车里,它就会到处乱按。你的任务就是确保这个熊孩子再怎么折腾,车机都不能死机。
4.2 常用参数详解
Monkey的参数很多,但常用的就那么几个。我挑重点讲,剩下的你们看文档就行。
| 参数 | 说明 | 示例 |
|---|---|---|
-p |
指定测试的包名。只测试一个应用时必用 | -p com.android.launcher |
-v |
日志详细级别。v越多越详细 | -v -v -v |
--throttle |
事件间隔,单位毫秒。不加的话事件会瞬间发完 | --throttle 300 |
-s |
随机种子。相同种子可复现相同事件序列 | -s 12345 |
--pct-touch |
触摸事件百分比 | --pct-touch 50 |
--pct-motion |
手势事件百分比 | --pct-motion 20 |
--pct-appswitch |
应用切换事件百分比 | --pct-appswitch 10 |
--pct-syskeys |
系统按键事件百分比 | --pct-syskeys 5 |
--ignore-crashes |
遇到崩溃不停止,继续测试 | --ignore-crashes |
--ignore-timeouts |
遇到ANR不停止,继续测试 | --ignore-timeouts |
我的经验:在座舱系统上,我建议把--pct-appswitch设高一点,比如15%~20%。因为座舱经常要在导航、音乐、电话之间来回切换,这个场景最容易出问题。我曾经遇到过切换时SurfaceFlinger崩溃,导致整个屏幕黑掉的情况。
4.3 脚本编写与执行
Monkey脚本其实不是必须的。但如果你想要更精细地控制测试流程,或者需要复现某个特定场景,那就得写脚本了。Monkey脚本本质上是一个事件序列文件,每一行代表一个事件。
4.3.1 脚本格式
Monkey脚本的格式很简单,我直接给个例子你们就明白了:
# 这是一个Monkey脚本示例
# 等待3秒
WAIT 3000
# 点击坐标 (500, 800)
TAP 500 800
# 从 (100, 500) 滑动到 (900, 500)
DRAG 100 500 900 500 10
# 按下返回键
PRESS BACK
# 按下HOME键
PRESS HOME
# 启动应用
LAUNCH com.android.settings
# 输入文本
TYPE HelloWorld
# 用户等待
USERWAIT 2000
嗯,这里要注意:WAIT和USERWAIT的区别。前者是脚本执行时的等待,后者是模拟用户思考的等待。在座舱测试中,我一般用USERWAIT,因为它更接近真实用户的操作节奏。
4.3.2 执行脚本
脚本写好后,通过以下命令执行:
adb shell monkey -f /sdcard/monkey_script.txt 1
注意最后的那个1,它表示脚本只执行一次。如果你想让脚本循环执行,可以写一个批处理脚本在外面包一层。
避坑指南:我曾经犯过一个低级错误——脚本里忘了加USERWAIT,结果事件发得太快,系统根本来不及响应。最后测出来的结果全是假的,浪费了一整天。所以,事件间隔一定要给够,尤其是座舱这种对实时性要求高的系统。
4.3.3 实战案例:座舱稳定性测试脚本
下面是我在MTK8676平台上用过的一个实际脚本片段。它模拟了用户开车时的典型操作:先看导航,然后切音乐,再调音量,最后接电话。
# 启动导航
LAUNCH com.baidu.navi
USERWAIT 5000
# 模拟导航界面点击
TAP 300 400
USERWAIT 1000
TAP 600 700
USERWAIT 2000
# 切换到音乐
PRESS HOME
USERWAIT 1000
LAUNCH com.tencent.qqmusic
USERWAIT 3000
# 调节音量
TAP 100 200
USERWAIT 500
DRAG 100 300 100 600 5
USERWAIT 1000
# 模拟来电
PRESS CALL
USERWAIT 2000
PRESS CALL
USERWAIT 1000
这个脚本跑一轮大概20秒。我一般会让它循环跑1000次,也就是大概5个半小时。如果中途没有出现ANR或崩溃,那这块的稳定性基本就稳了。
4.4 结果分析与常见问题
Monkey跑完后,你会看到一堆日志。怎么快速定位问题?我教你几招。
4.4.1 日志过滤
用grep过滤关键信息:
# 查看崩溃信息
adb logcat -d | grep -i "FATAL EXCEPTION"
# 查看ANR信息
adb logcat -d | grep -i "ANR in"
# 查看Monkey自身输出
adb logcat -d | grep -i "monkey"
4.4.2 常见问题类型
- NullPointerException:最常见,通常是某个对象没初始化就被调用了。我在座舱项目中遇到过,原因是某个Service在后台被杀死后,UI层还在引用它。
- WindowManager$BadTokenException:弹窗时Activity已经销毁。这个在快速切换应用时特别容易触发。
- SurfaceFlinger崩溃:座舱系统的老大难问题。通常跟硬件加速或图层合成有关。
- ANR:主线程被阻塞超过5秒。常见原因是IO操作或锁竞争。
我的建议:不要只看Monkey的最终结果。把日志保存下来,用grep把异常信息提取出来,按时间排序。你会发现很多问题其实是有规律的,比如总是在切换到某个特定应用时崩溃。这时候,你就可以针对性地写一个更精细的Monkey脚本去复现它。
4.5 小结
Monkey测试说白了就是“暴力测试”。但暴力不等于盲目。你要学会控制事件类型、频率和种子,让Monkey帮你找到那些隐藏的稳定性地雷。在MTK8676座舱系统上,我建议每周至少跑一次12小时的Monkey测试,配合--ignore-crashes和--ignore-timeouts参数,让它一直跑下去。你会发现,很多问题都是在第8小时、第10小时才冒出来的。
好,这一讲就到这里。下一讲我们聊聊压力测试中的内存泄漏检测,那也是个让人头疼的问题。