移动端自动化测试做到第三年,我越来越确信一件事:耗在维护脚本上的时间,比写脚本的时间多得多。录制回放工具看起来很美好,可一旦遇到动态布局、深链跳转、权限弹窗,录制回来的坐标就是一堆废数据;Page Object 设计模式虽然规范,但产品每改一次文案,我就要跟着改一次定位表达式。所以我一直盯着 AI Agent 在 Android 真机测试上的进展。Google 开源的 ARTEMIS 是其中比较值得研究的项目——它把 Agent、MCP 协议和 Android 设备命令空间串在一起,让测试人员不再逐条写步骤,而是直接把意图交给 Agent 去执行。
真正打动我的不是“AI 能代替人写用例”这个噱头,而是 ARTEMIS 把“测试任务”和“设备操作”之间那条又臭又长的链路打通了。这篇文章我会从三个层面展开:先讲为什么真机测试一直这么难,再拆解 ARTEMIS 的工作机制,最后给出一套可以直接落地的本地搭建、真机接入、CI 集成和避坑经验。
1. 真机测试的现状痛点:为什么录制回放和脚本维护让人抓狂
1.1 录制回放的效率幻觉
几乎每一个接触过移动端自动化的团队,都经历过那个“录制回放快速跑通 Demo”的阶段。你打开 Appium 或者 Android Studio 的录制器,点了几个按钮,生成一条测试用例,看起来效率极高。但放到真机上跑第二次,大概率就跪了:Button 的位置因为分辨率变化偏了几像素,网络延迟导致 Toast 没按预期弹出,某个控件被软键盘挡住,录制脚本的固定坐标就点偏了。
录制回放的本质是“把人的手指操作转成坐标和控件快照”,它假设页面在每次运行时都长一个样。真实世界不是这样的。动态接口返回的数据会影响列表高度,A/B 实验会影响文案和按钮顺序,系统弹窗会在任意时刻插入。录制回放在模拟器上、在刚开发完没有改动的版本上看着没问题,一旦进入真机矩阵、进入持续迭代阶段,稳定性立刻崩盘。
1.2 测试脚本的维护债务
后来大家改用 Page Object 模式,把元素定位抽到页面类里,似乎解决了坐标问题。但这只是把成本转移了。每个页面类里有十几个@FindBy注解,每个定位表达式都和产品的 DOM 结构、资源 ID、View 层级强绑定。产品经理改了一次文案、前端换了一个自定义控件,你的页面类就要跟着改;新同学接手时,要先读三个页面类才能看懂一条用例在干什么。
这套模式真正的价值不在“写起来爽”,而在“可维护”。但维护动作本身就是债务:每次 App 更新,你都要跑一遍全量回归,根据报错去改旧脚本,然后发现又有两个设备上因为系统字体不同导致布局错位。团队里最资深的人一半时间在写脚本,另一半时间在修脚本,留给探索性测试、性能分析的时间越来越少。
1.3 ARTEMIS 的定位:从“写脚本”到“下指令”
ARTEMIS 的出现,把问题从“每一步点哪里”拉高到了“要做成什么样”。你不再写“点击 id=a、输入 test、断言 text 等于 success”,而是直接告诉 Agent:启动 App,走到登录页,用指定的账号密码登录,然后确认首页出现用户名。
这个转变听起来简单,实际上对底层框架提出了很高的要求。Agent 需要能看懂屏幕截图,能读取 UI 层级信息,能调用设备操作工具,还能在动作失败后自己纠偏。ARTEMIS 不是用一个 Python 脚本硬编码这些能力,而是基于 MCP Server for Android,把设备能力标准化成一组工具,再接上具备视觉和推理能力的大模型 Agent。换句话说,它让“AI Agent 接管 Android 真机测试”从一个概念变成了可复现的工程方案。
对我个人而言,这套框架最重要的意义是它逼着测试团队重新思考用例结构:把注意力放在业务流程和验收条件上,而不是耗在定位器选择器上。
2. ARTEMIS 的工作机制拆解:Agent、MCP 与 Android 设备之间的三角配合
2.1 AI Agent 是大脑:自然语言如何变成操作规划
在 ARTEMIS 的架构里,最上层是 AI Agent。它接收的信息有两类:一类是用户给的自然语言测试目标,比如“验证设置页可以正常搜索蓝牙设备”;另一类是设备当前的状态,包括截图、UI 树、操作历史。
Agent 的核心动作不是“执行”,而是“规划”。每走一步它都要做一个类似这样的推理:当前页面显示的是设置主页,目标是要进入蓝牙设置,那么下一步应该点击“连接设备”或者“蓝牙”入口。模型需要综合视觉信息(截图里图标的位置)、结构信息(UI 树里的可点击节点)、语义信息(节点文本)来决定调用哪个工具。
这和我们写driver.findElement(By.id("bluetooth")).click()完全不同。后者是提前确定了“一定存在某个 id”,前者是现场观察、现场决策。所以 Agent 对截图质量和 UI 树完整度的依赖很高,这也是后面我会专门写“坑”的原因。
2.2 MCP Server for Android 是手和眼睛:设备能力被标准化成工具
MCP 在这里扮演的角色,我习惯用一个类比来理解:AI Agent 是大脑,MCP Server for Android 是它的手和眼睛。大脑不能直接操作手机,是 MCP Server 提供了一组“工具”,比如点击、长按、滑动、输入文本、获取当前页面截图、读取 UI 层级、启动应用、执行 adb shell 命令。
这套工具层的价值在于标准化。你在 ARTEMIS 里面对的是一组抽象工具,而不是五花八门的 adb 命令。Agent 不需要知道adb shell input tap x y的坐标换算逻辑,它只需要知道“点击屏幕上的某个元素”这个动作;MCP Server 会自己完成坐标解析和命令下发。
也正因如此,ARTEMIS 并不绑定某一种大模型。只要模型具备调用 MCP 工具的能力,理论上都能接入。官方默认链路里 Gemini 的效果比较稳,因为它的视觉理解能力足够强,但架构本身是开放的。这给团队后续替换模型、接入私有化部署留了空间。
2.3 Excubots 与规则引擎:从“执行用例”到“探索问题”
只看“执行一条指令”是不够的,Google 在 ARTEMIS 里还放了一个更野的东西:Excubots。我理解它是“探索型测试代理”,它不只是按指令一步一步走,而是自己去把一个 App 当成一个未知地图去探索。它能自动生成探索路径,进入不同页面,尝试不同操作,遇到崩溃、ANR、异常布局就记录现场并报告。
这个机制对真机测试特别有意义。传统的探索测试靠测试人员手动乱点,人很容易疲劳,而且很难覆盖到所有入口组合。Excubot 可以针对同一个 App 跑多轮探索,把发现的异常情况汇总成结构化报告。
规则引擎则用来约束 Agent 的行为边界。比如“系统权限弹窗出现时必须先记录再处理”“连续 5 步没有页面状态变化就停止任务”“不能点击状态栏下拉区域”。没有这些规则,Agent 很容易陷入无效循环或者做出危险操作,规则引擎是在“让 AI 干更多活”和“别让 AI 闯祸”之间找平衡。
2.4 一次完整执行链路:从指令到截图断言
把整个执行链路串起来看,一套典型的 ARTEMIS 运行流程是这样的:
- 我输入自然语言任务,比如“打开计算器,依次输入 7+8,断言结果等于 15”。
- Agent 收到任务,通过 MCP Server 获取当前设备和 App 状态,包括截图和 UI 树。
- Agent 根据状态规划第一步动作,调用 MCP Server 的启动应用工具。
- MCP Server 执行
adb shell am start,返回新的页面状态。 - Agent 看到计算器界面,决定点击数字 7,再点击加号,再点击数字 8。
- 完成输入后,Agent 通过截图识别出结果区域,判断数字是否为 15,并把结果写进测试输出。
- 整个过程的操作日志、截图、模型推理摘要、最终结论都会被保存下来。
这里最关键的一点是:Agent 不是一次性生成一整条脚本,而是一边执行一边观察。如果中间某个按钮没找到,它会换个路径重试;如果出现了系统弹窗,它会先处理弹窗再继续。这种闭环能力正是传统自动化框架最缺的东西。
3. 本地搭建与真机接入:跑通第一条自然语言测试用例
3.1 环境准备:Python、JDK 与 Android SDK
ARTEMIS 的安装方式和 Python 生态里的多数工具一样,建议用虚拟环境隔离。基础环境需要三样东西:Python 3.10 以上、JDK(用于 Android 工具链的签名和包解析)以及 Android SDK 里的 platform-tools。
Android SDK 这块,日常做 Android 开发的人应该都有,没有的可以用 Android Studio 里的 SDK Manager 安装。重点是要确保adb在环境变量里,ANDROID_HOME配置正确。我自己的习惯是把 platform-tools 路径直接加进 PATH,并且在 shell 里验证一下:
adb --version如果能看到 adb 版本信息,说明工具链没问题。JDK 版本不需要和 Android 开发完全一致,但建议用 JDK 17 这种常见版本,避免后面处理 APK 或者读 Android 系统信息时出现兼容问题。
3.2 安装 ARTEMIS 与配置模型 API Key
安装本身很直接,按官方 README 的方式执行即可。大致是克隆仓库、创建虚拟环境、安装依赖。装完之后要配置模型 API Key,让 Agent 能和一个支持视觉理解的大模型服务对话。设置方式通常是环境变量:
export GOOGLE_API_KEY="你的 API Key"这里有个很容易忽略的点:ARTEMIS 的 Agent 依赖“看截图”,所以模型必须支持图像输入,而不是随便一个纯文本模型。你在自测的时候如果用了一个不支持视觉的模型,最典型的症状就是 Agent 反复说“我无法看到页面内容”,然后开始瞎猜。
配置好之后,可以用一个最简单的指令跑通链路。我建议选一个你设备上一定存在的系统应用,比如计算器或者设置。第一轮的目的是验证 Agent、MCP Server、adb 这条链路是通的,而不是验证测试逻辑,所以指令越简单越好。
3.3 真机连接与测试前置设置
真机比模拟器多很多不确定性,所以我在接入 ARTEMIS 之前会先做几件前置准备。先用adb devices确认设备被正确识别;然后关掉锁屏和休眠,防止 Agent 跑到一半设备熄屏;还会把开发者选项里的“不保留活动”关掉,避免页面状态不稳定。
以下命令是常见的测试机准备动作:
adb devices adb shell wm dismiss-keyguard adb shell settings put global stay_on_while_plugged_in 3 adb shell settings put system screen_off_timeout 1800000这些命令的目的很简单:让设备在测试期间保持唤醒、不锁屏。否则 Agent 第一次截图看到的是一块黑屏,它会严重怀疑自己的视觉能力,然后疯狂重试。
3.4 执行一条真实用例:从打开 App 到结果断言
设备准备好之后,执行命令的核心无非是指定设备、描述任务、指定输出目录。以系统计算器为例,我会写这样的任务描述:
“打开计算器,点击数字 7,点击加号,点击数字 8,点击等号,然后检查结果区域是否显示 15。如果结果不是 15,记录失败原因并截图。”
我一般不用“点一下、点两下”这种机器人式描述,而是把验收条件写进去。ARTEMIS 的 Agent 会自己用截图和 UI 树去确认最终状态,这比传统断言更接近人的操作方式。
跑完之后去输出目录翻一遍,通常会有截图序列、操作日志、模型响应等文件。第一次跑通后,我对 ARTEMIS 的态度从“看热闹”变成了“真有可能用于生产”:它确实能动态适应页面状态,而不是死板地执行坐标。
4. 真机测试中比模拟器多出来的那些“坑”
4.1 权限弹窗、系统对话框与 adb 输入的限制
真机最烦人的就是各种系统级弹窗。新安装的 App 第一次启动时,可能会弹定位权限、存储权限、电话权限;系统更新后可能出现“系统界面已停止运行”;测试过程中还可能突然弹出“是否允许 USB 调试”之类的对话框。
这些弹窗会打断 Agent 的推理,因为它会把弹窗当成业务页面,继续寻找任务相关的按钮,然后找不到。
我常用的处理方式有三种。第一种是在跑测试之前,用 adb 把目标 App 的权限预先授予,避免弹窗出现:
adb shell pm grant com.example.app android.permission.ACCESS_FINE_LOCATION第二种是在任务描述里明确告诉 Agent:“如果出现系统权限弹窗,先点击允许”。这相当于给 Agent 一份弹窗处理预案。第三种是接受弹窗存在,把它当成测试的一部分——毕竟真实用户也会遇到,Agent 怎么处理本身就值得记录。
但请注意,不要用个人主力机来跑这类测试。因为 ARTEMIS 的 Agent 拥有执行 adb shell 命令的能力,这意味着它理论上可以做任何设备级操作。测试机就是测试机,数据风险要隔离。
4.2 坐标与分辨率:为什么“看到”和“点不到”是两回事
Agent 通过截图“看到”屏幕,但点击动作最终要落到具体的设备坐标上。模拟器通常分辨率固定,真机却是百花齐放:同一款 App 在 1080p 和 2K 屏幕上,按钮的像素位置完全不同。
ARTEMIS 的优势在于它优先读取 UI 树,通过控件节点定位元素,而不是纯靠像素坐标。如果控件的 bounds 信息可靠,Agent 就可以计算出该点击的坐标。但问题出在自绘 UI 上。Flutter、Unity、游戏引擎这类自绘框架,在 UI 树里经常只暴露一个巨大的容器节点,没有细分控件信息。这时候 Agent 只能退回到“看图猜坐标”,精度就会下降。
我遇到这种情况,会调整任务描述让 Agent 先确认当前截图和预期页面的偏差,并且每步操作后都主动截一张图验证结果。关键是接受“这类页面无法做到 100% 稳定命中”,把它标记为高风险场景,后续人工复核。
4.3 设备断连、App 崩溃与超时恢复
真机测试跑了二十分钟后,USB 连接可能松动;App 可能在某个深度路径上崩溃;adb server 可能因为日志刷屏而卡住。这些问题在模拟器上几乎不会出现,在真机上一晚上能遇到八百回。
我至少会做三件事来降低影响:一是测试前检查 USB 连接质量,能用 WiFi adb 的地方尽量用 WiFi adb,减少物理接触;二是写一个看门狗脚本,定期通过adb shell echo ok检查设备是否在线,如果掉线就自动adb reconnect;三是在每条任务里设置最大步数和超时时间,避免 Agent 卡在某个状态里无限重试。
最典型的一幕是:Agent 在一个页面连续点击同一个按钮五次,每点击一次页面内容都没变化,它还在继续。没有超时和操作次数上限,这条任务会一直烧 token 直到耗尽。规则引擎和外部超时要一起上,才能真正控制住 Agent 的行为。
4.4 中文输入、输入法切换和剪贴板边界
如果你测试的是国内 App,很多场景绕不开中文输入。而真机上用adb shell input text输入中文,大概率会乱码或者根本没输进去,因为这条命令本身就是给 ASCII 字符准备的。
我实测下来的处理思路是让 Agent 优先尝试“复制粘贴”路径:先把目标文本放到系统剪贴板,再通过长按输入框唤起粘贴菜单。这个链路在多数原生输入框上都行得通,但在自绘控件和 WebView 里依然可能失效。
更稳妥的做法是提前在测试机上装一个支持 adb 控制的输入法,并把系统默认输入法切过去。这样 MCP Server 每次执行输入工具时,走的是输入法通道,而不是裸调input text。这一条如果你不提前处理,跑中文用例时会极其痛苦:Agent 根本不知道为什么输入了,页面却一片空白。
| 场景 | 典型问题 | 应对方式 |
|---|---|---|
| 权限弹窗 | 系统弹窗打断 Agent 推理 | 预授权 + 任务描述内给出弹窗预案 |
| 自绘 UI | UI 树信息缺失,点击靠猜图 | 标记高风险场景,关键步骤加截图复核 |
| 设备断连 | USB 不稳、adb 卡死 | WiFi adb + 看门狗脚本 + 自动 reconnect |
| 中文输入 | input text 乱码 | 剪贴板粘贴 / 受控输入法替换 |
5. 把 ARTEMIS 接入测试流程:批量任务、多设备并行与 CI 门禁
5.1 让一批自然语言用例尽快跑起来
单条指令能跑通之后,下一步一定是要批量跑起来。我不建议用一个 Python 脚本粗暴地逐条调用,因为每一条任务都可能跑十几步,中间一步卡住会影响整批进度。更好的方式是给每条任务独立的输出目录,互不干扰,这样即使某条任务失败,现场也完整保留。
一个简单的外层循环大概长这样:
for task in "打开设置并关闭蓝牙" "进入存储页面检查可用空间" "搜索应用商店并安装一个小应用"; do artemis run \ --device-serial "$DEVICE_SERIAL" \ --instruction "$task" \ --output-dir "./runs/$(echo $task | md5sum | cut -c1-8)" done这只是演示,但它能说明一个核心思路:任务与输出目录一一对应。后续做结果聚合时,就不用猜哪条任务用了哪个目录。
5.2 多设备并行:并行的是设备,不是单线程 Agent
很多人问“AI Agent 怎么扛并发”。在 ARTEMIS 这种场景里,并发并不是让一个 Agent 同时操作 100 台设备,而是让多个 Agent 实例各管一台设备。每个实例独占一个设备串号,拥有独立的上下文和输出目录,互不共享状态。
所以并行能力的瓶颈其实在设备和模型 API 配额。你需要一个设备池,把几十台真机接入同一个 adb server;然后再控制 API 调用的每秒请求数,避免被限流。我的经验是刚开始不要追求数量,而是保证每个并行任务都有隔离环境:设备隔离、上下文隔离、输出隔离。
如果你们的测试设备有限,更务实的用法是“一台设备顺序跑一批关键路径任务”,而不是强行堆并行。AI Agent 测试的瓶颈通常在模型推理延迟上,并行起来之后,你卡住的往往不是设备,而是 API 服务的并发限制。
5.3 集成到 Git 工作流与质量门禁
把 ARTEMIS 接进 CI 的套路和传统自动化测试类似:代码合并触发、跑关键路径回归、汇总结果、决定是否阻塞发布。但有一点要特别注意:Agent 生成的测试不是一个固定耗时的任务,它可能因为探索路径不同而时快时慢。CI 里不能写死“五分钟跑完”,要给足超时预算,同时设置成本上限。
一个示例的 GitHub Actions job 看起来可以是:
jobs: android-regression: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup and run ARTEMIS run: | pip install -e . export GOOGLE_API_KEY=${{ secrets.GOOGLE_API_KEY }} adb devices artemis run --device-serial "$DEVICE_SERIAL" \ --instruction "完成关键路径回归" \ --output-dir "./runs" - name: Upload test artifacts uses: actions/upload-artifact@v4 with: name: artemis-runs path: ./runsCI 里最关键的不是跑起来,而是结果判定。Agent 的结论通常是自然语言,比如“任务完成”或者“页面出现异常”。你需要写一层解析器,把这种结论映射成 pass/fail/blocker,再传给质量平台的 API。否则测试结果只是一堆截图,没法驱动发布决策。
5.4 产物与报告:截图、操作轨迹、失败分类
ARTEMIS 这类 Agent 测试最值钱的地方,不在于“跑了多少条用例”,而在于“留下了多少现场数据”。我在实际使用中会把每个 run 目录当成一个完整的事故现场看待,里面至少要有这几类信息:
- 每一步操作前的截图,用来回放 Agent 当时的视野;
- 每一步调用的 MCP 工具和参数,用来判断 Agent 为什么这么操作;
- 模型的推理摘要,用来了解 Agent 决策依据;
- 最终结论和原始输入指令,用来对应业务需求;
- 设备信息、App 版本、模型版本,保证可重放。
失败分类也很重要。我把常见的失败分成三类:设备问题、Agent 问题、业务问题。设备问题比如 adb 掉线,Agent 问题比如模型连续无效规划,业务问题比如 App 真的崩溃了。前两类要修框架,第三类才是真正要提给研发的 bug。
6. 冷静看待 AI Agent 接管真机测试:能力边界与落地路线
6.1 当前最明显的软肋
ARTEMIS 目前还不适合定义成“测试用例的最终形态”,它更像是“探索需求的补充工具”。最明显的软肋有三个:
第一,动作序列不稳定。同一个任务,两次跑的动作路径可能不一样。模型有随机性,页面状态有微小差异,这导致结果很难做到传统测试那样的“绝对可重复”。第二,token 成本不可控。一次深度探索可能消耗大量模型输入,如果长时间无人值守,账单会很难看。第三,对自绘 UI 的掌控力有限。前面说了,Flutter、Unity 这类页面拿不到细粒度 UI 树,Agent 只能依赖视觉猜坐标,稳定性和盲人摸象差不多。
不能神化它,尤其不要觉得开源了就能直接替代 Appium 或 UIAutomator。它是一个新物种,不是旧工具的升级版。
6.2 建议优先采用的场景
根据我实际用的感受,ARTEMIS 最适合用在三个场景。
第一个是探索性测试。每次发版前,让 Agent 在设备上自由探索主要功能页,找崩溃和 ANR,这比人肉探索覆盖更广。第二个是核心路径冒烟。把登录、支付、消息列表这类核心链路写成自然语言用例,用 ARTEMIS 跑一遍,发现页面状态异常就截图留证。第三个是产品验收条件直接转需求,产品经理写的“用户可以完成下单流程”这种话,本身就是 Agent 可以理解的任务描述,省去测试用例翻译脚本的环节。
至于大规模、需要精确断言、重复运行一万遍的场景,传统自动化仍然是更稳的选择。两者不是替代关系,是互补关系。
6.3 给团队的落地建议
如果要引入 ARTEMIS,我建议按三个阶段走。
第一阶段,只做试点。挑一个非核心但足够复杂的业务模块,跑一周探索任务,收集崩溃数据和 token 消耗数据,评估收益。第二阶段,接设备池。把真机接入全流程,做权限基线、设备清理、断连恢复,形成稳定的可运行环境。第三阶段,接质量平台。输出标准化报告,打通 CI 门禁,和已有的缺陷管理系统关联。
最后说一句我自己的体会:AI Agent 接管 Android 真机测试之后,测试工程师的角色没有消失,但会明显转变。不再需要花大量时间去维护定位表达式,而要把精力花在“设计任务、定义验收、审核 Agent 行为”上。这个转变对资深测试来说其实是好事,因为终于可以把时间放在更有判断力的环节上,而不是跟一个resource-id死磕到底。ARTEMIS 是这种转变里一个很值得研究的技术样本,建议手头有真机测试需求的团队,拿一台闲置设备先跑跑看。