30、综合实战项目:从零搭建一个 ADB 自动化测试工具(需求分析、脚本编写、结果汇总)
终于到了最后一章。说实话,前面学了那么多 ADB 命令和脚本技巧,如果不把它们串起来做个真家伙,总觉得少了点什么。
这一章,我们就从零开始,搭建一个完整的 ADB 自动化测试工具。我会带着你走一遍完整的流程:先想清楚要做什么,再动手写脚本,最后把结果整理得漂漂亮亮。
需求分析:先想清楚再动手
我见过太多人上来就写代码,写到一半发现方向错了。我自己也吃过这个亏——有一次花了两天写了个自动化脚本,结果发现连最基本的设备连接检查都没做,跑起来全是报错。
所以,我们先花点时间做需求分析。这个工具要解决什么问题?说白了,就是帮我们自动完成重复性的测试工作,比如:
- 批量安装/卸载应用
- 自动执行 Monkey 压力测试
- 抓取日志并分析关键信息
- 生成测试报告
嗯,需求明确了。那工具应该长什么样?我个人习惯用 Python 写,因为它的 subprocess 模块调用 ADB 非常方便。你想想看,Python 加 ADB,简直就是自动化测试的黄金搭档。
核心需求清单:
- 支持多设备并行测试
- 可配置测试参数(如 Monkey 事件数、包名等)
- 自动检测设备连接状态
- 测试结果汇总为 HTML 报告
- 错误日志自动截取保存
整体架构设计
先画个图,让你对整个工具的结构有个直观认识。这个图我改了好几版,最终定下来三层架构:
脚本编写:核心代码实现
架构清楚了,接下来就是动手写代码。我会把核心模块拆开来讲,每个模块都配上完整的代码示例。
1. 设备检测模块
这个模块负责检测连接的设备。我曾经遇到过一个问题:脚本跑了一半,设备突然断开了,结果后面的测试全白费了。所以,我习惯在每次执行测试前都做一次设备状态检查。
import subprocess
import re
def get_devices():
"""获取已连接的设备列表"""
result = subprocess.run(['adb', 'devices'], capture_output=True, text=True)
lines = result.stdout.strip().split('\n')[1:]
devices = []
for line in lines:
if line.strip() and 'device' in line:
device_id = line.split('\t')[0]
devices.append(device_id)
return devices
def check_device_online(device_id):
"""检查指定设备是否在线"""
result = subprocess.run(
['adb', '-s', device_id, 'get-state'],
capture_output=True, text=True
)
return result.stdout.strip() == 'device'
小技巧:用 adb -s <设备ID> 指定设备,可以避免多设备时的混乱。我一般会在脚本启动时打印出所有设备列表,让用户选择要测试的设备。
2. Monkey 测试执行模块
Monkey 测试是 Android 压力测试的标配。但直接跑默认参数很容易出问题——我记得有一次忘了设置包名,结果 Monkey 把系统应用也测了,手机直接卡死重启。
def run_monkey_test(device_id, package_name, event_count=5000):
"""在指定设备上运行 Monkey 测试"""
cmd = [
'adb', '-s', device_id, 'shell',
'monkey', '-p', package_name,
'--throttle', '200',
'--ignore-crashes',
'--ignore-timeouts',
'-v', '-v', str(event_count)
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
return result.stdout, result.stderr
注意:Monkey 测试默认会发送大量随机事件,建议加上 --throttle 200 参数,让每次操作间隔 200 毫秒。不然事件太快,设备反应不过来,容易产生假阳性崩溃。
3. 日志抓取与分析模块
测试跑完了,日志怎么处理?我见过有人直接扔给开发一个几百 MB 的 logcat 文件,开发看了直摇头。正确的做法是:自动过滤出关键信息,比如崩溃堆栈、ANR 日志等。
def capture_logcat(device_id, output_file, filter_keyword='FATAL|ANR|CRASH'):
"""抓取日志并过滤关键信息"""
cmd = ['adb', '-s', device_id, 'logcat', '-d']
result = subprocess.run(cmd, capture_output=True, text=True)
with open(output_file, 'w', encoding='utf-8') as f:
for line in result.stdout.split('\n'):
if re.search(filter_keyword, line, re.IGNORECASE):
f.write(line + '\n')
return output_file
结果汇总:生成漂亮的测试报告
测试结果汇总,说白了就是要把数据变成人能看懂的东西。我个人习惯生成 HTML 报告,因为可以直接在浏览器里打开,还能加一些样式和交互。
下面是一个简单的报告生成函数:
def generate_report(device_id, test_results, output_path='report.html'):
"""生成测试报告"""
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>ADB 自动化测试报告</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; }}
.pass {{ color: green; }}
.fail {{ color: red; }}
table {{ border-collapse: collapse; width: 100%; }}
th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
th {{ background-color: #4CAF50; color: white; }}
</style>
</head>
<body>
<h1>测试报告 - {device_id}</h1>
<table>
<tr><th>测试项</th><th>结果</th><th>详情</th></tr>
"""
for item in test_results:
status_class = 'pass' if item['status'] == '通过' else 'fail'
html_content += f"""
<tr>
<td>{item['name']}</td>
<td class="{status_class}">{item['status']}</td>
<td>{item['detail']}</td>
</tr>
"""
html_content += """
</table>
</body>
</html>
"""
with open(output_path, 'w', encoding='utf-8') as f:
f.write(html_content)
return output_path
完整脚本整合
把上面的模块拼起来,就是一个完整的自动化测试工具了。下面是一个简单的入口函数:
def main():
# 1. 检测设备
devices = get_devices()
if not devices:
print("没有检测到设备,请检查连接")
return
print(f"检测到 {len(devices)} 台设备:{devices}")
# 2. 选择设备(这里简单起见,用第一台)
device_id = devices[0]
# 3. 执行测试
print(f"开始在 {device_id} 上执行测试...")
stdout, stderr = run_monkey_test(device_id, 'com.example.app', 10000)
# 4. 抓取日志
log_file = capture_logcat(device_id, 'crash_log.txt')
# 5. 生成报告
test_results = [
{'name': 'Monkey 测试', 'status': '通过' if 'Monkey finished' in stdout else '失败', 'detail': stdout[:200]}
]
report_path = generate_report(device_id, test_results)
print(f"测试完成,报告已生成:{report_path}")
if __name__ == '__main__':
main()
避坑指南:我曾经在生成报告时忘记处理编码问题,结果中文全变成了乱码。记得在打开文件时加上 encoding='utf-8',不然 Windows 系统上很容易翻车。
测试结果示例
跑完一次测试后,生成的报告大概长这样:
| 测试项 | 结果 | 详情 |
|---|---|---|
| 设备连接检测 | 通过 | 设备 emulator-5554 在线 |
| Monkey 压力测试 | 通过 | 执行 10000 事件,0 次崩溃 |
| 日志抓取 | 通过 | 抓取到 3 条警告日志 |
| 应用安装测试 | 失败 | INSTALL_FAILED_UPDATE_INCOMPATIBLE |
嗯,看到这个表格,你就能一目了然地知道哪些测试通过了,哪些出了问题。这就是自动化测试的意义——把重复劳动交给机器,把分析决策留给人。
说实话,这个工具虽然简单,但已经能覆盖日常工作中 80% 的自动化测试需求了。你完全可以基于这个框架,加上自己的业务逻辑,比如自动截图、性能数据采集等。记住,工具是死的,思路是活的。
公众号:蓝海资料掘金营,微信deep3321