
移动端自动化测试做到第三年我越来越确信一件事耗在维护脚本上的时间比写脚本的时间多得多。录制回放工具看起来很美好可一旦遇到动态布局、深链跳转、权限弹窗录制回来的坐标就是一堆废数据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 的出现把问题从“每一步点哪里”拉高到了“要做成什么样”。你不再写“点击 ida、输入 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 运行流程是这样的我输入自然语言任务比如“打开计算器依次输入 78断言结果等于 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 SDKARTEMIS 的安装方式和 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 推理预授权 任务描述内给出弹窗预案自绘 UIUI 树信息缺失点击靠猜图标记高风险场景关键步骤加截图复核设备断连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/checkoutv4 - 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-artifactv4 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 是这种转变里一个很值得研究的技术样本建议手头有真机测试需求的团队拿一台闲置设备先跑跑看。