移动端UI自动化这个领域,凡是真正动手维护过脚本的人,估计都有一段被元素定位支配的回忆——不是脚本写得不好,而是App一改版、文案一调整、弹窗一弹出,辛辛苦苦写的用例就崩给你看。最近一周,我把某科技巨头新开源的AI自动化框架(下文先统称AOM)引入到一个正在维护的App项目里,和团队原来用的老牌开源框架做了同场对比。整个过程既解决了不少老框架长期解决不好的问题,也踩了一些文档里根本没写的坑。这篇就把它的核心原理、迁移实操、真实数据和最终取舍一次讲清楚,给正在纠结要不要引入AI自动化测试的团队一点参考。
1. 老框架的三座大山,也是新框架要解决的问题
传统UI自动化框架本身并没有什么问题,它最大的问题其实是把太多责任扔给了写脚本的人。用户要自己定位元素、自己处理等待、自己适配机型、自己维护脚本。这些问题在项目小的时候还能忍受,一旦用例数量上去、版本迭代提速,就成了压在测试团队头上的三座山。
1.1 脆弱的元素定位:UI一改,脚本就崩
传统框架的定位方式,核心就是靠ID、Class、XPath、坐标这一套。它们的特点是“确定性强”,元素在哪儿就是哪儿,找不到就报错。但反过来,任何UI调整都可能让这些定位失效。
我印象很深的一次是,产品把一个按钮的文案从“立即下单”改成了“去结算”,结果整套下单流程的脚本挂了将近一半。原因很简单,很多用例里用的是包含文案的XPath表达式,比如//*[@text='立即下单'],文案一改表达式全部失效。
这种问题不是个例,而是常态。尤其在国内互联网团队的迭代节奏下,UI基本每两周变一次。测试同学每天花大量时间改的并不是用例逻辑,而是各种定位表达式。老框架的定位机制本质上是在跟UI的“表象”打交道,表象一变,脚本就要跟着返工。
1.2 被严重低估的脚本维护成本
很多人计算自动化测试成本时,只算了写脚本的时间,忽略了维护的时间。但真正上线跑过的人都知道,一个用例从写好到稳定运行,后续改动的工时往往比最初编写要多得多。
一个跨端的App产品,iOS和Android端如果是两套技术栈,同一个功能就要维护两套定位逻辑。如果再加上不同屏幕尺寸、不同系统版本,定位表达式的组合数量会爆炸。我见过一个团队,40条核心用例,每次版本回归前都要先花一到两天修脚本,否则CI根本跑不起来。
这里面的真实成本,按人天算非常可观。假设40条用例中20%在版本改动后需要修复,每条用例平均需要改2个定位表达式,一个测试工程师一天能稳定处理8个左右,那么一次改版就要搭进去一个人天。一个月两次版本,就是两个人天打底,一年下来几百人天的隐性成本,都消耗在“改定位”这种毫无技术含量又绕不开的事情上。
1.3 环境依赖和驱动管理是隐形负担
还有一个容易被忽略的痛点,是环境问题。传统框架依赖驱动和被测App的版本严格匹配。Android端偶尔会碰到驱动版本和系统版本不兼容,iOS端要处理一堆签名和权限问题。这些开销发生在跑用例之前,浪费很多时间,而且和用例本身质量没关系。
我在一个CI环境里遇到过特别典型的案例:用例脚本完全没变,只是基础镜像里升级了某个底层依赖,结果所有用例在启动阶段全部失败。排查了大半天,发现是驱动版本不匹配。这类问题在老框架的日常运维里几乎无法避免,属于生态成熟但结构老化的通病。
老框架的这些痛点,AOM基本都用AI能力做了针对性设计。下面这张表是我自己的理解,比较直观:
| 痛点 | 老框架的处理方式 | AOM的解决思路 |
|---|---|---|
| 元素定位 | 依赖ID、XPath、坐标等固定标识 | 基于页面语义和视觉内容识别目标 |
| 脚本维护 | 需要人工逐个修改失效表达式 | 用自然语言描述动作,底层自动适配 |
| 环境依赖 | 驱动版本与应用版本强相关 | 减少预装依赖,降低驱动版本耦合 |
| 异常处理 | 找不到元素直接抛异常 | 自动尝试备选定位,失败后自愈 |
2. AI框架的核心原理:它如何把页面“看懂”
老框架解决的是“怎么让机器按指令点击”,AOM解决的是“怎么让机器理解页面该点什么”。这个差异听起来不大,但实现路径完全不同。
2.1 从层级树到语义建模
传统框架拿到的是一个界面层级树,类似一个包含所有控件坐标、大小、文本信息的XML结构。它能看到的就是“这个页面有一个按钮,文本是登录,坐标是(x,y)”。这种信息是精确的,但也是孤立的,它不理解这个按钮在整个页面流程里的角色。
AOM的做法是把页面当作一个语义对象来处理。它先拿到界面层级树,然后通过大模型把层级树“翻译”成一份页面语义模型,大概描述出“当前页面是什么页面,有哪些关键操作区域,它们的意图分别是什么”。这一步相当于把一张地图变成了对地形的理解。
打个比方,传统框架是“按门牌号找人”,门牌号一换就找不到;AOM更像是“看脸认人”,哪怕这个人换了套衣服、换了发型,只要核心特征还在,依然能认出来。这也是AOM在UI小改动后依然能稳定定位的底层原因。
2.2 三级定位策略:DOM语义、OCR文本、视觉匹配
AOM的定位不是单一策略,而是三级递进的机制:
第一级是DOM语义匹配。框架先尝试从界面层级树里找到符合语义描述的目标节点。比如你说“点击登录按钮”,它会找到文案为“登录”且控件类型为Button的节点。这是性能最好、最精确的一条路径。
第二级是OCR文本匹配。如果DOM树里找不到完全匹配的节点,或者页面内容被绘制在无法暴露文本信息的容器中,框架会先截屏,然后通过OCR识别屏幕上的文本位置,再根据文本位置推算出可点击区域。这个机制能有效应对一部分自绘控件场景。
第三级是视觉模板匹配。当文本信息也不可靠时,比如目标是一个没有文字的图标按钮,AOM会根据之前成功执行过的截图记忆做视觉相似度匹配。这相当于给框架装了一双眼睛,能识别“长得像”的目标。
这三条路径并非串行死等,而是并行启动、以置信度最高的结果为准。所以在实际体验中,AOM的定位速度并不像想象中那么慢,反而因为多路校验,成功率更稳。
2.3 意图驱动的动作生成与异常自愈
老框架的用例是命令式的:你先告诉它在哪里,再告诉它做什么。AOM的用例是声明式的:你直接告诉它这一步的目标是什么,它自己规划动作序列。
我用一个实际例子说明。老框架写“登录”大概是这样的结构:
# 传统写法:每一步都要告诉框架“去哪里找元素” driver.find_element_by_id("login_name").send_keys("testuser") driver.find_element_by_id("login_pwd").send_keys("123456") driver.find_element_by_id("login_btn").click() driver.find_element_by_xpath("//*[@text='首页']").click()AOM的写法变成了这样:
from aom import Agent agent = Agent(session="legacy_demo") agent.step("在登录页输入用户名 testuser") agent.step("输入密码 123456") agent.step("点击登录按钮") agent.step("等待首页加载完成,点击底部导航中的首页Tab")它背后的执行逻辑是:先把这些自然语言拆解成动作意图,再结合页面语义模型去实时匹配执行目标。如果第一次执行失败,框架会自动收集错误截图、分析失败原因,然后尝试用备选定位路径重新执行。这个过程就是所谓的“自愈”。
我在实测中看到过一个很典型的场景:按钮文案从“确认支付”改成了“立即付款”,老框架直接报元素不存在,AOM靠语义理解依然准确点击了目标。这种体验对长期维护脚本的人来说,冲击力非常直观。
| 对比维度 | 传统框架 | AOM |
|---|---|---|
| 用例表达 | 面向元素的命令式指令 | 面向目标的结果式描述 |
| 定位机制 | 固定标识符匹配 | 语义、OCR、视觉多路并行 |
| 失败处理 | 直接抛异常终止 | 自动分析原因并尝试自愈 |
| 维护成本 | 每次UI变动都可能返工 | 非结构性改动通常可自动适配 |
3. 把老项目迁到AOM的实操步骤,以及我踩进去的三处坑
原理讲得再好,落地才是关键。这一周我专门做了一件事:把团队里一套跑了一年的老框架用例迁移到AOM上,记录每一步操作和遇到的问题。整个过程有惊喜也有翻车。
3.1 环境准备与接入方式
AOM的安装比我预想中轻量很多。它不需要我们手动去匹配各种驱动版本,而是由框架自带一套运行时环境管理逻辑。整个接入流程从零开始大概半小时就能跑通。
# 安装框架命令行工具 pip install aom-agent # 初始化项目结构,生成配置文件 aom init --project legacy_demo # 检查当前环境是否满足运行条件 aom doctor # 连接被测App并启动会话 aom run --app com.example.demo安装完成后,它会先检查设备连接情况、必要权限、以及GPU或模型运行环境。我用的是一台普通的Windows工作站加一台Android真机,不需要额外配置复杂的依赖链。这点相比老框架那种“安装主程序、装驱动、装客户端、配环境变量”的流程,体验好了不是一点半点。
3.2 用例改写:从“找元素”到“描述意图”
迁移过程中最需要适应的是心智模式的变化。老框架的用例核心是“找元素”,AOM的用例核心是“描述结果”。如果写用例的时候脑子里还在想用什么XPath,就体会不到这套框架的优势。
我拿团队里最常维护的一段下单用例做迁移示范。原来的脚本里有七八个定位表达式,逻辑大概是:点击商品、进入详情、点击加入购物车、点击去结算、填写地址、提交订单。迁移到AOM之后,每一步只需要描述动作意图,它自己会去匹配页面状态。
这里面有一个特别重要的习惯:描述动作时要带上结果目标,而不是只写动作本身。比如不要写“点击按钮”,要写“点击结算按钮并进入订单确认页”。这样既方便框架校验执行结果,也方便后续人阅读用例。
3.3 坑一:模型冷启动慢,CI里容易被超时杀掉
第一个坑出现在第一次执行用例的时候。AOM启动后需要把模型加载到内存,这个冷启动过程非常慢,我实测大约40秒到1分钟。在本地手动跑还能接受,但在CI环境里,任务通常有启动超时限制,模型还没加载完,任务就被判定失败杀掉了。
解决办法是给AOM增加预热机制。具体做法是让Agent服务常驻,提前加载好模型,后续用例全部走这个常驻进程。如果一定要按需启动,也要在CI脚本里单独设置一个预热步骤,把超时时间拉长。
# 先执行一次预热命令,等待模型加载完成 aom warmup --session legacy_demo这个坑不算难解,但它很典型:AI框架的特性是“启动慢、执行稳”,不能按照老框架那种“随启随用”的思维去用。
3.4 坑二:弹窗干扰目标识别,OCR把提示文字当成操作按钮
第二个坑比较隐蔽。某次实测中,App启动后弹了一个运营弹窗,弹窗上写着“立即领取”,而页面上正好有一个“立即支付”按钮。AOM的OCR识别把弹窗里的“立即”当成了主页面上的操作入口,点错了位置,用例跟着跑偏。
这类问题本质上不是定位精度不够,而是页面上下文理解不足。框架只看到了“有一块区域写着立即”,但没意识到这是弹窗不是主页面按钮。解决思路是主动给框架配置页面级的弹窗处理策略。
agent.set_modal_handler( trigger=["领取", "跳过", "我知道了"], action="close" )告诉框架当页面里出现这类特征文本时,先把它当作弹窗关闭,再去识别真正的业务目标。配好之后,这个问题基本没有再出现过,但需要每个项目根据自己的弹窗特征单独配置,这个工作量省不掉。
3.5 坑三:自绘控件没有语义,需要提前“教学”
第三个坑出现在一个图表页面上。被测App有一个用Canvas自绘的订单趋势图,图上没有任何文本节点,DOM树里找不到对应的控件信息,OCR也读不出有效文本,AOM完全无法理解这个图表区域。
这种场景下,最关键的操作是“教学”。AOM提供了一种方式,可以人工告诉它某个区域是什么控件、具有什么行为。整个思路很像教一个新同事认东西:第一次需要你带路,后面它自己就能处理同类场景。
agent.teach( element="订单趋势图", rule="当页面出现包含网格线和折线的区域时,识别为订单趋势图", fallback="截取该区域内坐标,执行点击操作" )这类自定义控件如果数量少,教学成本可以接受。但如果被测App大量使用自绘UI,教学工作量就会明显上升,这算是AOM当前的一大适用边界。
4. 一周同场实测:稳定性、速度、维护成本的真实对比
只有原理和踩坑还不够,我做这次评测最关键的目标是拿到一组可以横向对比的数据。所以我把AOM和老框架放在同一台设备、同一个网络环境、同一批用例条件下跑了一轮,尽量控制变量。
4.1 测试环境与样本说明
被测对象是一个正在维护中的社区类App,外加一个电商类Demo。我抽了20条核心业务用例,覆盖登录、刷信息流、查看帖子、发帖、下单、支付结果确认等关键链路。
对照组是团队里已经稳定运行了一段时期的老框架脚本,这20条用例全都有对应的现成脚本。AOM这边由我手工迁移了同样业务路径的用例,确保两者覆盖的操作步骤一致。
硬件条件统一用同一台Android真机,执行期间关闭无关后台进程,每轮执行前都重启App、清理缓存,尽量减少环境因素造成的误差。
4.2 核心数据结果
| 指标 | 老框架 | AOM |
|---|---|---|
| 首次全量执行耗时 | 约32分钟 | 约26分钟 |
| 执行通过率 | 85%(17/20) | 95%(19/20) |
| 失败后自愈成功用例数 | 0条 | 3条 |
| 一次版本改版后脚本修复人天 | 约6人天 | 约1.5人天 |
| 环境搭建时间 | 1.5天 | 0.5天 |
说明一下统计口径。通过率指的是一次完整执行中不需要人工干预、脚本自动跑完所有步骤的比例。自愈成功指老框架已经失败、但AOM通过备选定位或重试机制继续跑完的用例。样本量不大,结论只能代表我这个项目的具体情况,但趋势已经足够说明问题。
从数据看,AOM在首次执行耗时上并没有巨大优势,只快了大概20%,主要因为模型推理本身有额外开销。它的核心优势体现在通过率和维护成本上,尤其是改版后的修复人天从6人天降到1.5人天,这个差距对长期运营测试脚本的团队来说非常关键。
4.3 翻车场景:新框架并没有全面碾压
AOM在20条用例里确实赢了,但也有几条场景它表现得很挣扎,甚至不如老框架。这些翻车点同样值得记录。
第一个是低端真机上的冷启动速度。在老框架下,页面加载完成后可以立刻执行下一步操作。但AOM在低端机上做视觉识别时,单次推理耗时明显变长,如果页面还在播放转场动画,它很容易把动画中间帧当成最终页面状态,导致误判。
第二个是转场动画频繁的页面。老框架可以通过显式等待严格控制时机,AOM的自适应等待策略在动画复杂时反而不够敏感,偶尔会提前点击,踩在动画尚未结束的节点上。这类问题需要额外配置等待条件才能消除。
第三个是自绘控件和图表类区域。前面提到过,这类区域在AOM里既没有DOM语义也没有OCR文本,如果没做“教学”,成功率基本为零。而老框架虽然也需要特殊处理,但它至少能用坐标定位,处理路径相对固定。
4.4 翻车背后的原因
这些翻车场景反过来印证了一个判断:AOM的优势在“灵活”,劣势在“不确定性”。AI识别本质上是概率性的,它在语义理解上远超老框架,但在需要精确控制执行节奏、像素级验证、绝对确定性的场景里,反而不如传统方案可靠。
老框架是确定性的执行引擎,每一步都有明确指令,失败就是失败,不会骗你。AOM是概率性的理解引擎,它对大部分场景处理得很好,但一旦遇到不熟悉的页面形态,可能出现“看起来很合理但实际不对”的错误。测试团队要接受这种不确定性的存在,不能把它当成银弹。
5. 要不要跟风换框架?我的取舍建议
实测做完之后,团队里立刻出现了两种声音:一种认为AOM几乎可以全面替换老框架,另一种觉得它还不够成熟,不过是炒作。我在两边都待过,说说现在的真实判断。
5.1 适合切换到AOM的团队
如果你所在的团队符合下面几个特征,那么AOM值得认真评估:
- App版本迭代频繁,UI改动多,老框架的脚本维护已经成为负担
- 团队测试人力紧张,没有足够时间持续维护大量定位表达式
- 现有UI自动化覆盖率不高,希望通过降低脚本编写门槛来提升覆盖率
- 测试对象以信息流、表单、电商等具有明确语义结构的页面为主
- 愿意接受模型推理带来的少量额外耗时,不追求极致的执行速度
对这类团队来说,AOM最大的价值不是替你把所有事情都做了,而是把脚本维护成本从“人人讨厌的苦力活”降到“偶尔看一眼的辅助工作”。
5.2 不建议切换的团队
反过来,如果你所在的团队有下面这些特征,现阶段不建议大规模迁移:
- 执行环境对耗时极度敏感,比如每次CI都有严格的超时预算
- 测试对象大量使用游戏画布、自绘图表、不规则交互控件等缺乏语义结构的页面
- 已有成千上万条稳定运行的老框架脚本,迁移成本远大于维护成本
- 需要像素级视觉验证、控件精确坐标断言等功能
- 团队对AI输出结果没有足够信心,要求每一步操作都可解释、可复现
这些场景下,老框架的确定性反而是优势。AOM引入后大概率会产生新的维护负担,而不是解决原来的负担。
5.3 渐进式迁移:不要一夜之间推翻重来
我建议的方式不是“全量迁移”,而是三层渐进。
第一层,选三条团队中维护成本最高的核心用例,用AOM重写,和现有脚本并行跑两周。这个阶段只做验证,验证通过率、执行耗时、维护工时的真实变化。
第二层,新功能模块的UI自动化用例,默认用AOM的语义化写法编写,逐步积累新框架下用例的覆盖范围,同时老框架维持原有用例不动。
第三层,确认AOM在稳定性、易用性上都能满足要求后,再按模块逐步把老框架用例替换下来。替换过程中始终保留任意一条用例的回滚通道,也就是老框架脚本不立刻删除,只是暂时封存。
5.4 对生态现状的冷静判断
最后说一个容易被人忽略的点:AOM这类项目虽然解决了很多老框架的痛点,但它目前的生态成熟度整体还在早期。插件数量、周边工具、社区案例都远不如老框架丰富,文档里也会有一些细节写得不够清楚,遇到问题通常需要自己看源码或翻社区讨论。
引入AOM不是“装个包就能解决一切”,它需要团队有人愿意承担新工具的学习成本和框架本身的排障成本。我这一周在坑里爬出来的经验就是:项目初期要预留一定的探索时间,不要一上来就定KPI,等基础环境稳定了再谈规模化落地。
这周实操下来,我最大的体会是:AOM真正改变的其实是测试用例的思维方式。过去我们写的是“机器如何执行”,现在写的是“业务想要什么结果”,后者显然更贴近测试的本质。如果你手上正有一套天天在改定位表达式的老脚本,不如先抽三条最痛苦的用例试一试AOM,用两周时间拿真实数据说话,再决定要不要走下去。AI自动化现在确实不是神话,但也远没到可以无脑崇拜的程度,试过、对比过、踩过坑,才有资格评判它适不适合自己的项目。