Monkey稳定性测试
Monkey 稳定性测试 完整学习大纲
一、Monkey 测试概述
1.1 Monkey 测试的定义与起源
- 什么是 Monkey 测试:一种伪随机的用户事件流生成工具,通过模拟用户的触摸、手势、按键等操作,对 Android 应用进行压力测试和稳定性测试。
- 名称来源:像猴子一样随机乱点,测试应用的抗压能力和异常处理能力。
- 开发者:Google Android 团队开发,集成在 Android SDK 中。
1.2 Monkey 测试的核心价值
- 发现崩溃 (Crash) 和无响应 (ANR) 问题
- 验证应用在异常输入和连续操作下的稳定性
- 评估应用的健壮性和容错能力
- 在压力场景下暴露内存泄漏、性能瓶颈
- 回归测试的快速验证手段
1.3 Monkey 测试的应用场景
- 应用发布前的压力测试
- 竞品分析时的稳定性对比
- 长期运行的稳定性测试
- 多场景组合的压力测试
- 自动化测试流水线中的稳定性检查环节
1.4 Monkey 与其他测试工具对比
| 特性 | Monkey | MonkeyRunner | UI Automator | Appium |
|---|---|---|---|---|
| 测试类型 | 稳定性/压力测试 | 功能测试 | 功能测试 | 功能测试 |
| 脚本支持 | 无 | Python脚本 | Java/JUnit | 多语言 |
| 事件控制 | 随机 | 精确控制 | 精确控制 | 精确控制 |
| 学习成本 | 低 | 中 | 中 | 高 |
| 跨应用 | 支持 | 支持 | 支持 | 支持 |
二、环境搭建与基础使用
2.1 环境要求
- Android SDK:必须安装,包含在
platform-tools中 - adb 工具:Android Debug Bridge
- 测试设备:真机或模拟器,开启 USB 调试
- 待测应用:已安装的 APK 文件
2.2 环境检查
# 检查 adb 是否安装
adb version
# 检查设备连接
adb devices
# 查看设备上安装的应用包名
adb shell pm list packages | grep "your.app"
# 检查 Monkey 是否可用
adb shell monkey -h
2.3 第一个 Monkey 测试
# 基本语法
adb shell monkey [options] <event-count>
# 示例:对包名为 com.example.app 的应用发送 1000 个随机事件
adb shell monkey -p com.example.app 1000
2.4 测试结果解读
- 测试成功完成:显示
Events injected: 1000 - 应用崩溃:显示
CRASH信息 - 应用无响应:显示
ANR信息 - 其他异常:权限问题、强制关闭等
三、Monkey 参数详解
- 基础参数
# 指定测试的应用包 -p <package_name> # 示例:测试指定应用 adb shell monkey -p com.example.app 1000 # 测试多个应用 adb shell monkey -p com.app1 -p com.app2 1000 # 测试所有应用 (不推荐,可能造成系统异常) adb shell monkey 1000 - 事件类型参数
# 指定各类型事件百分比 # 格式:--pct-<事件类型> <百分比> adb shell monkey \ --pct-touch 40 \ # 触摸事件 --pct-motion 25 \ # 滑动事件 --pct-trackball 5 \ # 轨迹球事件 --pct-nav 10 \ # 导航事件 --pct-majornav 10 \ # 主要导航事件 --pct-syskeys 5 \ # 系统按键 --pct-appswitch 3 \ # 应用切换 --pct-anyevent 2 \ # 任意事件 --pct-pinchzoom 0 \ # 双指缩放 --pct-permission 0 \ # 权限事件 --pct-rotation 0 \ # 屏幕旋转 1000 - 调试参数
# 设置随机种子 (seed) # 相同种子产生相同的事件序列,用于复现问题 -s <seed> adb shell monkey -s 12345 1000 # 设置事件延迟 # 每个事件之间的延迟时间(毫秒) --throttle <milliseconds> adb shell monkey --throttle 500 1000 # 设置超时时间 # 在指定时间(秒)后停止测试 --timeout <seconds> adb shell monkey --timeout 300 10000 - 约束参数
# 忽略超时 (忽略ANR) --ignore-timeouts # 忽略崩溃 (忽略Crash) --ignore-crashes # 忽略安全异常 --ignore-security-exceptions # 监控本地代码崩溃 --monitor-native-crashes # 杀死超时进程 --kill-process-after-error - 高级参数
# 设置日志级别 -v (简单) -v -v (详细) -v -v -v (最详细) adb shell monkey -v -v 1000 # 禁用状态栏 --pkg-blacklist-file <file> # 禁用通知栏 --pkg-whitelist-file <file> # 设置应用无响应超时时间(毫秒) --hprof
四、Monkey 事件类型详解
- 触摸事件 (Touch Events)
- 事件类型:
--pct-touch <percent> - 描述:模拟用户在屏幕上的单点触摸操作
- 包含操作:点击、长按
- 最佳实践:一般设置为 40-50%,模拟用户最常见的操作
- 事件类型:
- 手势事件 (Motion Events)
- 事件类型:
--pct-motion <percent> - 描述:模拟用户在屏幕上滑动、拖拽的操作
- 包含操作:上下左右滑动、任意方向滑动
- 最佳实践:设置为 20-30%,测试列表滚动、页面切换
- 事件类型:
- 轨迹球事件 (Trackball Events)
- 事件类型:
--pct-trackball <percent> - 描述:模拟轨迹球操作,已很少使用
- 最佳实践:现代设备可设为 0 或较小值
- 事件类型:
- 基本导航事件 (Nav Events)
- 事件类型:
--pct-nav <percent> - 描述:模拟导航设备的基本操作
- 包含操作:上、下、左、右方向键
- 最佳实践:设置为 5-10%
- 事件类型:
- 主要导航事件 (Major Nav Events)
- 事件类型:
--pct-majornav <percent> - 描述:模拟导航设备的主要操作
- 包含操作:返回键、菜单键
- 最佳实践:设置为 5-10%
- 事件类型:
- 系统按键事件 (Syskeys)
- 事件类型:
--pct-syskeys <percent> - 描述:模拟系统按键操作
- 包含操作:Home键、音量键、电源键
- 最佳实践:设置为 5-10%
- 事件类型:
- 应用切换事件 (Appswitch)
- 事件类型:
--pct-appswitch <percent> - 描述:模拟应用切换操作
- 最佳实践:设置为 5-10%,测试应用前后台切换
- 事件类型:
- 其他事件类型
- 缩放事件:
--pct-pinchzoom - 权限事件:
--pct-permission - 旋转事件:
--pct-rotation - 任意事件:
--pct-anyevent
- 缩放事件:
五、Monkey 脚本编写
5.1 Monkey 脚本基础
- 脚本文件格式:纯文本文件,每行一个命令
- 脚本作用:定制化的事件序列
- 脚本优势:可重复执行、可版本控制
5.2 脚本事件语法
# 基本格式
<command>; <delay>; <component>; <x>; <y>;
# 示例
DispatchPointer(0,0,0,500,500,0,0,0,0,0,0,0);
UserWait(2000);
DispatchPress(KEYCODE_BACK);
5.3 常用脚本命令
# 点击事件
DispatchPointer(downTime,eventTime,action,x,y,pressure,size,metaState,xPrecision,yPrecision,deviceId,edgeFlags);
DispatchPointer(0,0,0,100,200,0,0,0,0,0,0,0); # 在(100,200)位置点击
# 按键事件
DispatchPress(keycode);
DispatchPress(KEYCODE_HOME); # 按Home键
DispatchPress(KEYCODE_BACK); # 按返回键
# 等待
UserWait(milliseconds);
UserWait(2000); # 等待2秒
# 输入文本
DispatchString(input);
DispatchString("Hello World");
# 启动Activity
LaunchActivity(pkg, clz);
LaunchActivity(com.example.app, com.example.app.MainActivity);
5.4 脚本示例
# 保存为 monkey_script.txt
# 启动应用
LaunchActivity(com.example.app, com.example.app.MainActivity);
UserWait(2000);
# 点击登录按钮
DispatchPointer(0,0,0,300,500,0,0,0,0,0,0,0);
UserWait(1000);
# 输入用户名
DispatchString("testuser");
UserWait(500);
# 按返回键
DispatchPress(KEYCODE_BACK);
UserWait(1000);
# 执行脚本
adb shell monkey -f /sdcard/monkey_script.txt 1
六、Monkey 测试策略
6.1 测试场景设计
- 冒烟测试:少量事件快速验证
- 稳定性测试:长时间大量事件
- 压力测试:高频率事件
- 兼容性测试:不同设备、系统版本
- 回归测试:每次发布前执行
6.2 事件比例配置策略
# 推荐配置 - 模拟真实用户
触摸事件: 40%
手势事件: 25%
基本导航: 10%
主要导航: 10%
系统按键: 5%
应用切换: 5%
其他: 5%
# 游戏应用配置
触摸事件: 60%
手势事件: 20%
系统按键: 10%
其他: 10%
# 工具类应用配置
触摸事件: 30%
手势事件: 20%
基本导航: 20%
主要导航: 20%
系统按键: 5%
应用切换: 5%
6.3 测试时长与次数规划
- 快速测试:1000-5000 个事件
- 标准测试:10000-50000 个事件
- 深度测试:100000+ 个事件
- 时长建议:5分钟 - 24小时不等
6.4 多设备并行测试
# 获取设备列表
devices=$(adb devices | grep -v "List" | awk '{print $1}')
# 并行执行
for device in $devices; do
adb -s $device shell monkey -p com.example.app 10000 &
done
# 等待所有测试完成
wait
七、测试结果分析
7.1 日志级别与输出
# 不同详细级别的日志
adb shell monkey -p com.example.app -v 1000 # Level 0
adb shell monkey -p com.example.app -v -v 1000 # Level 1
adb shell monkey -p com.example.app -v -v -v 1000 # Level 2
# 输出到文件
adb shell monkey -p com.example.app 1000 > monkey_log.txt
7.2 关键信息提取
# 成功完成
Events injected: 1000
# 发送种子
:Sending rotation degree=0, persist=false
# 事件统计
:Monkey: seed=12345 count=1000
# 异常信息
// CRASH: com.example.app (pid 12345)
// ANR: com.example.app (pid 12345)
7.3 崩溃分析
- Java Crash:Java层崩溃
- Native Crash:Native层崩溃
- ANR:应用无响应
- Force Close:强制关闭
7.4 日志分析工具
# 过滤崩溃信息
grep -i "crash" monkey_log.txt
grep -i "anr" monkey_log.txt
grep -i "exception" monkey_log.txt
# 统计事件类型
grep "Sending" monkey_log.txt | wc -l
# 提取错误堆栈
grep -A 20 "FATAL EXCEPTION" monkey_log.txt
7.5 性能监控
# 监控CPU
adb shell top -d 1 | grep com.example.app
# 监控内存
adb shell dumpsys meminfo com.example.app
# 监控电池
adb shell dumpsys battery
八、高级技巧与最佳实践
- 避免误操作系统应用
# 创建白名单 echo "com.example.app" > /sdcard/whitelist.txt adb push whitelist.txt /sdcard/ # 创建黑名单 echo "com.android.settings" > /sdcard/blacklist.txt echo "com.android.phone" >> /sdcard/blacklist.txt adb push blacklist.txt /sdcard/ - 结合其他工具使用
# 结合logcat收集日志 adb logcat -c adb logcat -v time > app_log.txt & adb shell monkey -p com.example.app 10000 kill %1 # 结合systrace分析性能 python systrace.py -a com.example.app -o trace.html monkey - 自动化测试集成
#!/usr/bin/env python3 import subprocess import time import os def run_monkey_test(package_name, event_count, seed=None): """执行Monkey测试""" cmd = ["adb", "shell", "monkey", "-p", package_name] if seed: cmd.extend(["-s", str(seed)]) cmd.extend(["-v", "-v", "--throttle", "100", "--ignore-crashes", "--ignore-timeouts", str(event_count)]) log_file = f"monkey_{package_name}_{int(time.time())}.log" with open(log_file, "w") as f: result = subprocess.run(cmd, stdout=f, stderr=subprocess.STDOUT, text=True, timeout=3600) return result.returncode, log_file def analyze_log(log_file): """分析日志文件""" with open(log_file, "r") as f: content = f.read() if "CRASH" in content: return "CRASH" elif "ANR" in content: return "ANR" else: return "PASS" if __name__ == "__main__": package = "com.example.app" for i in range(10): # 执行10轮测试 print(f"第{i+1}轮测试开始...") retcode, logfile = run_monkey_test(package, 5000, seed=i*1000) result = analyze_log(logfile) print(f"第{i+1}轮测试结果: {result}") - 测试报告生成
import json from datetime import datetime def generate_report(test_results): """生成测试报告""" report = { "project": "Monkey Test Report", "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "summary": { "total_tests": len(test_results), "pass_count": sum(1 for r in test_results if r["result"] == "PASS"), "crash_count": sum(1 for r in test_results if r["result"] == "CRASH"), "anr_count": sum(1 for r in test_results if r["result"] == "ANR"), }, "details": test_results } with open("monkey_report.json", "w") as f: json.dump(report, f, indent=2, ensure_ascii=False) return report - 最佳实践总结
- 设置合适的种子:便于问题复现
- 合理的事件比例:模拟真实用户行为
- 添加适当延迟:避免事件过快
- 忽略非关键异常:专注于稳定性测试
- 监控系统资源:及时发现性能问题
- 保存完整日志:便于问题分析
- 多轮次测试:提高问题发现率
- 版本对比测试:验证修复效果
九、常见问题与解决方案
- 权限问题
# 错误:java.lang.SecurityException: Permission Denial # 解决方案: # 1. 添加忽略安全异常参数 adb shell monkey --ignore-security-exceptions ... # 2. 授予必要权限 adb shell pm grant com.example.app android.permission.xxx - 设备无响应
# 设备卡死时强制重启 adb reboot # 杀死Monkey进程 adb shell ps | grep monkey adb shell kill <pid> - 测试中断
# 网络断开重连 adb kill-server adb start-server adb devices # 应用崩溃后继续测试 adb shell monkey --ignore-crashes ... - 结果不一致
# 相同种子产生不同结果 # 原因:设备状态、应用状态不同 # 解决方案:测试前重置应用状态 adb shell pm clear com.example.app
十、扩展与进阶
- Monkey 与其他工具结合
- Monkey + Appium:混合测试框架
- Monkey + Jenkins:持续集成
- Monkey + Python:自动化测试框架
- Monkey + Shell:批量化测试
- 自定义 Monkey
- 修改源码:Android开源项目
- 添加新事件类型
- 自定义事件分布
- 集成业务逻辑
- 云测试平台
- Firebase Test Lab
- AWS Device Farm
- 百度MTC
- Testin
- 机器学习优化
- 智能事件生成
- 异常模式识别
- 自适应测试策略
- 预测性分析
十一、学习资源
11.1 官方文档
- Android Developers:Monkey 官方文档
- Android SDK:源代码和工具
- GitHub:开源项目和示例
11.2 在线教程
- Google Testing Blog
- Android Testing Guide
- 各大技术社区专栏
11.3 书籍推荐
- 《Android 测试之道》
- 《移动App测试实战》
- 《Google软件测试之道》
11.4 实践项目
- 构建自动化 Monkey 测试框架
- 实现 Monkey 测试结果分析平台
- 开发 Monkey 测试报告系统
- 集成到 CI/CD 流水线
- 多设备集群测试系统
11.5 社区资源
- Stack Overflow
- GitHub Issues
- Android Testing Community
- 各大公司技术博客