移动端自动化:测试中最常用的 ADB 命令应该怎么组织成可复用能力
上一篇我讲了,为什么 Android 测试值得先把 ADB 这层基础能力打好。这一篇继续往下走,不再讨论“该不该做”,而是直接讨论一个更现实的问题:
测试里最常用的 ADB 命令,到底应该怎么组织,才能真的变成可复用能力,而不是一堆散乱脚本。
一开始接触 ADB,容易走两个极端:
- 一种是把 ADB 当命令手册,谁要用就自己搜命令
- 另一种是过早封装成很重的平台,但底层动作根本没梳理清楚
这两个方向最后都会出问题。
前者的问题是复用差、排障慢、不同人执行方式不一致;后者的问题是平台表面很完整,但一旦设备异常、命令超时、证据缺失,底层没有稳定能力支撑,平台只会把问题藏得更深。
所以更推荐的方式是:先把高频 ADB 动作按测试任务拆出来,形成一层稳定的“设备操作能力层”,再让脚本、流水线、平台去调用它。
一、不要按命令记忆 ADB,要按测试任务组织 ADB
如果只是从文档角度看,ADB 命令很多,但真实测试里高频出现的能力并没有那么分散。大多数时候,你真正反复用到的是下面几类任务:
- 设备发现与连通性检查
- 应用安装、卸载、清缓存、拉起
- 页面外输入与系统级控制
- 日志采集与证据留存
- 文件推送与结果回收
- 异常后的设备恢复
这几个任务看起来简单,但它们几乎覆盖了移动端自动化里最核心的“外围动作”。无论你后面接的是 Appium、自研框架、冒烟脚本,还是设备池调度,这些动作都绕不过去。
所以更稳妥的建议一直是:
不要让团队成员记一堆零散命令,而要让体系里沉淀出一套统一任务:
check_deviceinstall_appreset_applaunch_appcollect_logscapture_screenrecover_device
这样以后你换实现、换脚本语言、换执行平台,使用方都不用重新理解底层细节。
二、设备发现与连通性检查,是所有 ADB 自动化的第一层
写 ADB 脚本时,如果上来第一步就是安装 APK 或启动应用,这个顺序其实很危险。因为只要设备状态不稳定,后面的任何操作都有可能变成偶发失败。
所以更稳的做法通常是把设备检查做成统一前置任务。
最基础的命令是:
1 | adb devices -l |
这些命令看着普通,但在工程里有几个关键价值。
1. 先确认设备是不是 device,不要直接执行业务动作
你在 adb devices 里常见到的几种状态:
deviceofflineunauthorized- 根本查不到设备
这四种状态的处理完全不同。如果这一步不先分流,后面会出现大量误判。
比如:
offline往往是连接层问题或 ADB server 异常unauthorized本质上是授权弹框没处理- 查不到设备可能是 USB、驱动、端口映射、设备重启导致
2. 设备元信息要提前采集,不要等失败后再补证据
通常会在任务开始时就把这些信息采集下来:
- 序列号
- 机型
- Android 版本
- SDK 版本
- 电量
- 剩余存储空间
因为同一个用例在不同机型、不同系统版本上的表现很可能不同。如果不保留这些上下文,后面复盘时会很被动。
例如电量过低时,某些系统会自动限制后台行为;存储空间过低时,安装和截图都可能失败。这些都不是“用例逻辑错误”,但如果没有设备上下文,看起来就像随机故障。
3. 检查动作最好有超时和重试,不要让流水线无限卡住
ADB 的一个常见问题是命令本身未必报错,但会卡很久。尤其是:
- 设备刚重启
- USB 连接不稳定
- 无线调试链路抖动
- 设备被系统弹框阻塞
所以连通性检查必须有:
- 单次命令超时
- 限次重试
- 最终明确失败原因
否则 CI 上最容易出现的不是“直接失败”,而是一个任务长时间挂死。
三、安装、卸载、清缓存、拉起应用,是最应该标准化的动作
这是移动端测试里最常见的一组操作,也是最容易被写乱的一组操作。
常见命令包括:
1 | adb -s <serial> install -r app.apk |
这些命令如果放到真实项目里,不适合只当成临时操作,至少应该沉淀成下面几种标准任务。
1. install_app
这个任务最好不只是单纯执行 adb install,而是至少带上这些能力:
- 判断 APK 路径是否存在
- 安装前确认设备可用
- 识别安装返回结果
- 区分覆盖安装、首次安装、安装失败
- 在失败时保留错误输出
因为 ADB 安装失败的原因很多,比如:
INSTALL_FAILED_VERSION_DOWNGRADE- 存储空间不足
- 签名不一致
- 包损坏
- 设备离线
如果脚本只返回一个“安装失败”,后续几乎没法排查。
2. reset_app
这类任务通常比卸载重装更高频。大量测试场景只需要把应用状态重置,不需要重新安装。
常见动作是:
1 | adb -s <serial> shell pm clear com.example.app |
这个任务的价值在于:
- 成本比重装低
- 速度更快
- 适合回归和冒烟前清状态
但要注意一个边界:pm clear 清掉的是应用数据,不会处理系统权限弹窗、系统缓存异常、测试账号风控状态等问题。把“清数据”直接等同于“完全初始化”,这个判断并不成立。
3. launch_app
启动应用看上去简单,实际上是非常适合统一封装的动作。因为不同场景下启动方式不一样:
- 指定
Activity - 根据包名走
monkey - 启动后等待首屏稳定
- 启动失败后自动采证
更倾向把“启动成功”的定义也明确下来,比如:
- 应用进程已存在
- 指定页面 Activity 已进入前台
- 启动后若干秒内没有闪退
否则很多脚本只是把命令发出去了,但并没有真正确认应用处于可测状态。
四、输入控制与系统级操作,是做前置准备和恢复时最常用的一层
移动端测试里的不少动作,其实不需要依赖 UI 框架才能完成。尤其是设备准备、简单输入、系统级控制,ADB 往往更直接。
常见命令包括:
1 | adb -s <serial> shell input tap 540 1680 |
这一层能力在测试中最典型的用途有四种。
1. 做简单前置准备
比如:
- 解锁屏幕
- 回到桌面
- 点击开发测试入口
- 输入账号或验证码
这些动作如果只是作为用例前置,没必要都交给完整 UI 自动化框架。
2. 快速恢复现场
用例跑挂以后,最常见的问题不是“功能错了”,而是设备现场脏了,比如:
- 还停留在异常页
- 弹窗没关
- 键盘挡住了控件
- 应用在后台挂起
这时候 keyevent、点击、强杀进程、回桌面这些动作非常实用。
3. 判断当前页面是不是对的
仅靠截图不一定能准确判断应用当前处于哪个页面。更常用的是:
1 | adb -s <serial> shell dumpsys window |
用它去看当前焦点页面、前台 Activity、任务栈状态,定位问题比纯看图快很多。
4. 做轻量化页面跳转
有些页面根本没必要从首页手点进去,而是可以直接通过 Activity、深链、广播去拉起。只要业务允许,这种方式会比纯 UI 点击更稳、更快。
但这里要注意一个边界:ADB 输入适合做辅助控制,不适合替代完整 UI 校验。
如果你的目标是验证页面元素、交互反馈、布局显示、控件状态,那还是应该交给更上层的自动化框架。
五、日志、截图、录屏和文件拉取,是失败后最值钱的证据链
的自动化脚本最大的问题不是执行失败,而是失败后没有证据。最终只能看到一行“case failed”,然后再让人手工复现。
这类问题最适合通过 ADB 提前补上证据链。
常用命令有:
1 | adb -s <serial> logcat -d |
1. 日志采集要区分“实时跟随”和“失败导出”
logcat 最常见的一种用法,就是把日志一股脑打印到控制台。这在个人排查时没问题,但放进自动化体系里不够用。
更稳的做法通常是分成两种模式:
- 执行前清空日志,执行中持续采集
- 失败后按设备和任务导出日志快照
这样做的好处是:
- 日志上下文更干净
- 更容易定位本次执行相关事件
- 可以把日志和截图、录屏一起挂到测试报告
2. 截图不要只在最后截一张
如果只在 case 失败后截一张图,很可能现场已经变了。更合理的方式是:
- 关键步骤失败立即截图
- 异常恢复前截图
- 恢复后再补一张图
这样你能知道失败发生在哪个阶段,也能知道恢复动作有没有生效。
3. 录屏适合定位间歇性问题,但要注意成本
录屏很有价值,尤其适合:
- 间歇性闪退
- 页面卡顿
- 动画或过渡异常
- 偶发点击失效
但它也有明显成本:
- 文件大
- 长时间录制影响设备性能
- 不及时清理会占满设备空间
所以录屏通常更适合作为失败补救能力,而不是默认全量开启。
六、文件推送与结果回收,是 没意识到的高频能力
除了操作设备本身,ADB 还有一类很常用但经常被低估的能力,就是文件交互。
常见命令:
1 | adb -s <serial> push local.json /sdcard/Download/local.json |
这类能力在测试里很常见,比如:
- 下发调试配置
- 导入 mock 数据
- 推送测试资源文件
- 拉取应用日志
- 拉取执行产物
很多临时排查动作,其实都可以先通过文件下发或回收完成,不一定非得让研发另开接口。
但这里有两个常见坑:
1. 路径权限和 Android 版本差异
不同 Android 版本、不同厂商 ROM,在外部存储访问上差异很大。如果脚本里把路径写死,换一台设备就可能失效。
2. 文件拉取成功,不代表内容有效
我见过不少脚本只判断 pull 是否成功,但实际拉回来的日志文件是空的,或者是前一次执行残留的数据。
所以文件回收不仅要判断“命令成功”,还要判断:
- 文件是否存在
- 文件大小是否合理
- 时间戳是否匹配本次执行
七、异常恢复任务要单独设计,不要把清理动作散落到各处
设备异常是移动端自动化里最常见的现实问题。如果没有统一恢复任务,脚本会越来越脏,因为每个人都会在不同位置偷偷塞一段“兜底命令”。
更合适的做法是专门定义 recover_device 这类任务,把恢复动作集中起来。
常见恢复动作包括:
1 | adb -s <serial> shell input keyevent 3 |
恢复任务通常分三层:
1. 轻恢复
- 回桌面
- 关闭目标应用
- 清临时文件
- 重新拉起应用
适合绝大多数普通失败场景。
2. 中恢复
- 清应用数据
- 重启 ADB 会话
- 重新识别设备
适合应用状态明显脏掉,但设备本身还正常的场景。
3. 重恢复
- 重启设备
- 标记设备不可调度
- 通知维护人介入
适合频繁 offline、录屏失效、系统卡死、存储异常等问题。
这套分层很重要,因为不是每次失败都值得直接重启设备。恢复成本太高,执行效率会被拖垮;恢复太轻,又会导致污染环境带进下一轮执行。
八、在项目里最常见的几类 ADB 实战坑
如果只在本机连一台设备跑几次脚本,ADB 看起来很稳定。但一旦进入批量执行、长时间运行、多人协作环境,下面这些坑会高频出现。
坑 1:命令能跑通,但结果不可靠
现象:
install成功了,但应用打不开pull成功了,但拉回的是空文件screenrecord没报错,但视频无法播放
根因往往不是“命令语法错了”,而是:
- 执行完成后没有校验结果
- 只看退出码,不看输出内容
- 文件是旧产物,不是本次执行生成的
修复思路:
- 每个关键任务都要定义结果校验
- 尽量检查输出内容、文件大小、时间戳、进程状态
- 不要把“命令执行成功”等同于“业务动作成功”
坑 2:多设备执行时,忘了强制带 -s
现象:
- 命令偶尔成功,偶尔跑到别的设备上
- 日志和截图对不上用例
- 设备池里互相串数据
这是非常典型的工程事故。只要环境里可能同时连多台设备,所有设备命令都必须强制带序列号。
这一点不能靠开发者自觉,必须在封装层统一做掉。
坑 3:日志越采越多,最后把机器和设备都拖慢
现象:
- 流水线越来越慢
- 日志文件越来越大
- 某些设备开始安装失败或截图失败
最后查下来,往往是:
logcat没清理- 录屏文件没删除
- 拉取日志后本地没归档清理
- 设备空间长期积压
这类问题本质上不是工具问题,而是资产清理策略没设计。
坑 4:把 ADB 当万能方案,结果边界失控
ADB 很强,但它不是所有移动端测试问题的解法。
比如:
- 元素定位准确性
- 页面渲染断言
- 复杂交互链路
- iOS 端统一方案
这些事情只靠 ADB 不够。
如果团队把所有移动端自动化都压到 ADB 上,最后会发现可维护性越来越差。它更适合作为设备层和辅助控制层,而不是替代一切。
九、更推荐的 ADB 能力分层方式
如果后面要接测试框架、Jenkins 或自研平台,建议把 ADB 这层能力至少分成下面三层。
1. 原子命令层
职责:
- 调
adb - 处理超时
- 捕获标准输出和标准错误
- 统一错误码
这一层不关心业务,只关心“命令有没有稳定执行”。
2. 任务能力层
职责:
- 设备检查
- 应用安装
- 清数据
- 拉起应用
- 截图
- 录屏
- 日志导出
- 设备恢复
这一层面向测试任务,是最值得沉淀复用的部分。
3. 场景编排层
职责:
- 冒烟前置准备
- case 失败自动采证
- 批量设备巡检
- 执行后环境回收
这一层和具体业务、测试流程绑定更紧。
分层的意义在于:
- 原子命令层坏了,容易替换
- 任务能力层稳定后,可被多个项目复用
- 场景编排层可以随着业务变化灵活调整
十、排查 ADB 问题时,可以按什么顺序走
这部分很重要。的问题不是不会写命令,而是一出故障就开始盲试。
通常可以按这条顺序排查:
1. 先看设备状态
确认:
- 是否能被识别
- 是否
device - 是否被别的任务占用
2. 再看命令有没有发到正确设备
确认:
- 是否带了
-s - 序列号是否正确
- 多设备环境是否串行/并行混乱
3. 再看执行动作是否真的完成
确认:
- 安装后应用是否存在
- 启动后进程是否在
- 文件是否真的生成
- 截图和日志是否是本次产物
4. 最后再看业务问题
很多所谓“业务失败”,其实在第三步之前就已经暴露出是设备层或证据层问题。
如果一开始就往业务逻辑上猜,排查会绕很远。
结语
ADB 在测试里最有价值的地方,不是“会不会敲几个命令”,而是你能不能把这些命令变成稳定、统一、可排障、可接入流水线的测试能力。
如果只是个人调试,命令会用就够了;但如果你希望它服务于团队、服务于自动化体系,就必须把它从“命令集合”升级成“任务能力层”。
这也是更准确地说的移动端工程化起点:
- 不追求一上来就做复杂平台
- 先把设备层能力做稳定
- 先把证据链补齐
- 先把恢复动作标准化
只有这样,后面无论你接 Appium、接设备池,还是接更复杂的移动端自动化框架,底层才不会一直塌。