UI 自动化:UI 自动化为什么容易脆弱,怎么治理

UI 自动化最常见的标签就是“脆”。围绕这个词,最常见的判断是:

  • UI 本来就不适合自动化
  • 浏览器脚本天然不稳定
  • 页面一改就没法维护

这些话不算全错,但也不够准确。治理过程里更容易看到另一件事:UI 自动化之所以脆,通常不是单一工具的问题,而是一组系统性波动源一起叠加的结果

也正因为如此,它不是“修某条脚本”就能解决的问题,而要从定位、等待、数据、环境、场景选择、失败留痕等多个方面一起收敛。

一、UI 自动化为什么会脆

通常把根因分成六类。

1. 定位脆弱

依赖长 XPath、动态 class、元素顺序,这类脚本天然容易被前端改动打断。

2. 等待脆弱

页面还没稳定,脚本已经在点按钮、做断言。很多随机失败,本质上是等待设计不够。

3. 数据脆弱

列表没数据、账号状态不对、目标对象不存在,这些都会让页面动作看起来失败,但根因其实在前置数据。

4. 环境脆弱

测试环境慢、服务偶发波动、弹随机提示、浏览器和驱动版本不一致,这些都会被 UI 自动化放大。

5. 场景设计脆弱

把超长链路、低频功能、快速迭代页面也纳入 UI 自动化,本身就是把维护成本拉高。

6. 失败留痕脆弱

脚本失败后,如果只有一条异常堆栈,没有截图、没有视频、没有 trace,维护者只能靠重跑猜问题。

二、为什么会误判根因

真实项目里,一个 UI case 失败后,最常见的处理方式是:

  • 重跑一次
  • 如果过了,就当环境问题
  • 如果没过,再加一点 sleep

这种处理方式短期省事,长期最危险。因为你会把所有问题都糊成“脚本不稳定”,最终团队对结果失去信任。

所以我后来治理 UI 自动化时,一直强调先做失败分层,而不是先修脚本。

三、怎么做治理,而不是头痛医头

真正有效的治理,通常要同时做下面几件事。

1. 定位治理

推动:

  • data-testid
  • 页面对象和组件对象分层
  • 统一定位规则

这一步的目标是减少前端变更直接打断脚本。

2. 等待治理

统一等待层,避免 case 自己乱写:

  • sleep
  • 临时轮询
  • 零散等待逻辑

把等待从“时间控制”升级为“稳定状态判断”。

3. 数据治理

给 UI 自动化准备:

  • 稳定账号
  • 稳定数据池
  • 必要的接口造数入口

否则大量失败会被脏数据和缺数据放大。

4. 环境治理

收口:

  • 浏览器版本
  • 驱动版本
  • 节点环境
  • 基础依赖

不要让脚本在不同节点上表现完全不一致。

5. 失败现场治理

固定保留:

  • 截图
  • video / trace
  • 当前 URL
  • console error
  • 页面源码或关键 DOM

这是把“失败不可解释”变成“失败可诊断”的关键。

6. 场景治理

定期做一件非常现实但 不愿意做的事:下线高噪声、低价值 case。

不是所有写出来的脚本都值得长期保留。

四、一个真实案例,为什么“加等待”并不能解决问题

假设一个“创建活动”脚本经常失败,最常见的处理动作是继续加等待。但通常会先把问题拆开:

  • 是按钮定位不稳定
  • 还是弹窗加载慢
  • 还是活动名称重复导致校验失败
  • 还是后端服务偶发慢
  • 还是浏览器节点资源紧张

如果根因是活动名重复,你加 10 次等待都没用;如果根因是弹窗未完全可交互,你只改数据也没用。

这也是为什么治理更适合从“失败分层”开始。

五、怎么定义“治理有效”

我不要求 UI 自动化像接口自动化一样稳定,但会用下面这些标准判断它是否进入“可维护状态”:

  • 随机失败明显下降
  • 同一条脚本本地和 CI 结果更接近
  • 失败后能快速知道大致是哪一类问题
  • 页面变更时,更多改动集中在页面对象层
  • 团队看到失败时,第一反应不再是“可能又误报了”

只要最后一点开始出现,说明治理已经在发挥作用。

六、怎么理解“UI 自动化本来就会脆”

我承认 UI 自动化不可能做到绝对稳定,但“它本来就脆”不能成为不治理的理由。

真正成熟的目标不是让它从不失败,而是:

  • 失败尽量真实
  • 失败尽量可解释
  • 高价值脚本尽量长期可维护

只要做到这三点,UI 自动化就已经能成为团队可信赖的一部分。

七、结语

UI 自动化脆弱,很多时候不是因为页面天然不能测,而是定位、等待、数据、环境、场景设计和失败留痕一起失控了。治理的重点不是不停修单条脚本,而是逐步压缩这些系统性波动源。只要治理方向对,UI 自动化完全可以从“偶尔能跑的脚本”变成“可长期信任的回归能力”。

本章延伸阅读