自动化真正烧钱的阶段不是"写",是"养"。一个普遍的行业体感是:套件跑起来后,团队七八成的自动化时间花在了失败用例的分析和维护上。CI 一轮跑完掉了二十条,你得逐条判断——产品真出 bug 了?flaky 重跑就过?环境挂了?是这次业务改版让旧脚本不再适配,还是脚本自己就写坏了? 这判断每天重复、耗神,还高度依赖老员工。
这一篇讲 AI 怎么一次接手:把整份失败日志丢给它,一轮完成分诊、聚类,并对大部分 flaky 直接给出根因和修法方向;人只处理真缺陷和少数疑难。
技术栈沿用系列:Python + Pytest + Playwright(建议开 pytest-rerunfailures,重跑结果是判 flaky 的硬信号)。方法论对 Selenium / Cypress / Appium 同样适用。
"用例红了"是结果,不是病因。红灯里通常混着四类,处置天差地别:
| 类别 | 典型特征 | 该往哪走 |
|---|---|---|
| 真缺陷(产品回归) | 断言业务值不符、确定性红、和本次改动相关 | 立即拦、提 bug,这是测试的本职战果 |
| flaky(不稳定) | 同一版本重跑结果不一致、时红时绿 | 挂账,按根因治理(本文重点) |
| 环境 / 数据问题 | 502、依赖服务挂、造数失败、DB 连不上 | 恢复环境,不该算到产品头上 |
| 脚本不适配 / 坏了 | 产品改版后流程、文案、定位器变了脚本没跟上;或定位器必现找不到、import 报错、封装改了没同步 | 修测试代码,不是产品问题 |
传统模式全靠人逐条点开日志。而这四类在日志里本就有可区分的硬信号,这是能整批交给 AI 的前提。
pytest 一轮跑完,失败堆栈、错误类型、rerun 的重跑记录都在文本日志里;再把每条失败的界面截图一起给 AI,两样就够分诊和判断大部分根因——几十上百条失败,现在的上下文一次装得下,不用逐条发。
截图是信息量最大的一手证据(Playwright 配 screenshot: only-on-failure 后失败现场自动落盘,CI 报告点开那条失败就能看到),现在模型本就多模态,直接贴图:是不是跳回了登录页、有没有弹窗/遮罩盖住、元素到底渲染没渲染、是不是落到了错误页面,很多根因看一眼图就定了,比读堆栈快得多,对"选择器 / 登录态 / 动画遮罩"这几类尤其管用。
日志和截图之外,有一样东西能顺手给就更好:本次改动的文件列表(git diff --name-only HEAD~1,CI 环境里一般能直接取)。它的作用是帮 AI 区分"红的模块刚好本轮被改过 → 更像产品真回归"还是"产品没动 → 更像脚本或环境问题"。不给也不影响分诊,需要时它会找你要。
还缺的现场材料,让 AI 看完第一轮自己点名:
trace.zip 是打包格式、录屏是视频,文本日志里只有路径——它要哪条,你再在 trace viewer 里把可疑步的 DOM/网络/控制台摘成文本,录屏发给带视觉的模型;如果一次失败量大到这些材料塞不下,或者想做成无人值守自动分诊,再让 AI 写个十几行的脚本解析 JUnit XML、按用例汇总失败清单并关联截图挂到 CI;日常几十条的规模,直接贴日志和截图最省事。
下面是本轮 CI 的失败材料:每条用例的错误类型、堆栈和重跑结果(日志),
以及每条失败的界面截图(可能还附了本次改动的文件列表,有就参考)。
请结合日志和截图一次性完成分诊,本轮不要改代码。
第一步·分诊:每条失败输出一行——
用例名 / 类别(真缺陷·flaky·环境数据·脚本问题 四选一)/ 置信度(高·中·低)/
判定依据(引用重跑结果、错误类型、堆栈首行、与 commit 的关联)/ 建议动作。
第二步·聚类:把 flaky 按根因标签(登录态、等待时序、数据耦合、选择器、
第三方接口、并发抢资源、时间日期、动画iframe…)聚类,多条同根因的归为一组。
第三步·对每个 flaky 簇直接给出:
最可能的根因 + 证据、推荐修法方向、还缺什么证据(证据充分就写"可直接修")。
最后给处理优先级:哪些必须人立刻看(疑似真缺陷、低置信),哪些可批量按修法处理。
铁律:
- "证据支持的判断"和"你的推测"分开标注;证据不足不许硬判,明确列出要我补的材料;
- 禁止把 time.sleep、retry、force=True、try/except 吞异常当作修法,那是掩盖。
【必须人立刻看】
- test_pay_amount 真缺陷/高 断言金额 99≠100,本轮 commit 碰了计价逻辑 → 拦截提bug
- test_refund_flow flaky/低 堆栈被截断、无 trace → 请补这条的 trace 和用例代码
【可批量处理·flaky 簇:登录态过期(6 条:test_enroll/test_coupon/…)】
- 现象:均 401 后跳登录,重跑通过,夜间跑高发
- 根因:storage_state 里的 token 过期,套件后半段才轮到的用例踩中
- 修法:登录态定时保鲜 + 并行按 worker/角色分配账号(详见 3.2)
- 结论:证据充分,改一处公共登录 fixture 可清 6 条,可直接修
【环境问题(8 条)】
- 均卡在支付沙箱超时,第三方沙箱故障 → 等恢复重跑,非产品问题,无需改码
【脚本问题(4 条:test_order_list/…)】
- 均 TimeoutError 必现找不到 .btn-submit,产品未改、本轮重构过下单页 → 定位器失效,改测试代码
价值一眼可见:二十条红灯,一轮被压成"1 条要立刻看的真缺陷 + 1 处封装改动清 6 条 + 一批等着恢复的环境故障 + 4 条改定位器的脚本问题 + 1 条待补料的疑难"。 人从逐条翻日志,变成只处理"真缺陷"和"低置信"两小撮。
边界:AI 的分类是分流建议不是判决。疑似真缺陷、要自动建 bug 单的,必须人确认。它把有明确信号的大部分快速归位,人集中火力在少数拿不准的上。
刚开始不信它很正常:头一两周先让 AI 分、人照常独立判一遍,再对照两者差异——重点不是看对错总数,而是看它在哪些根因上稳、哪些上飘。等你摸清它的可靠边界(通常登录态、选择器、环境这类有硬信号的很稳,跨模块数据耦合、罕见时序偏飘),就可以只复核"真缺陷 + 它自己标中低置信度"的那一小撮,其余直接按它的分流走。信任是这样一格一格放的,不是第一天全交。这个过程里,你每纠正它一次(团队怎么界定环境故障、哪些模块红灯必属真缺陷、哪类报错直接判脚本问题),就把这条口径回填进提示词或判定规则,它下一轮就更贴你的标准——分诊助手就是这样被你慢慢训练成可靠伙伴的。
大部分高置信 flaky 在第二章已经拿到根因和方向。只剩证据不足、需要深挖的少数,走这一段——注意是"少数",不是每条都来一遍。
按它列的清单补证据:trace 可疑步(取法见 2.1)、相关 Page Object/fixture/factory 代码、git diff、这条的历史红绿规律等。补回后让它在已有分诊结论上继续,不用从头再来。
根因就按下面这张地图对号入座(和分诊聚类用的标签一致),绝大多数 flaky 落在:
| 类别 | 典型症状 | 快速判据 |
|---|---|---|
| 等待 / 时序(最高发) | timeout、element detached | 红在找/点元素,慢机或并行更易红 |
| 数据 / 状态耦合 | 单跑绿、整套红、隔天红 | 依赖残留数据、用例顺序、共享可变状态 |
| 登录态 / 会话 | 偶发跳登录、401、被踢下线 | token 过期、storage_state 失效、同账号互踢 |
| 选择器 | 偶尔匹配 0 个或多个 | 动态 class、下标 xpath、文案会变 |
| 网络 / 第三方 | 接口超时、限流 | 红在等某接口,重跑常过 |
| 并发抢资源 | 只并行时红 | 固定账号、文件、端口、共用一条数据 |
| 时间 / 时区 / 日期 | 跨天、月底才红 | 用例里用了 now()、今天日期 |
| 动画 / 遮罩 / iframe / 新窗口 | 可见但点不到、句柄丢 | 系列前文讲过的传统老坑 |
下面按根因地图逐类给"怎么确认 + 怎么修",可以让 AI 对着那一簇失败逐行给修法候选和影响面,人来拍板。
① 数据、登录态——根子在公共层,改在 fixture/factory,别在红用例上补。 这两类不一定出现次数最多,却往往一改清一片:让 AI 把这一簇引用的公共方法读出来,定位是哪一个的问题、改它、再回归整簇。它在这里值钱的不是"帮你写个工厂"(那点代码人手写更快),而是顺着一簇红灯找到公共根因、说清影响面。
数据先选对造数方式,运行时主流就这几种,稳定性取舍不同:
| 造数方式 | 做法 | 稳定性取舍 |
|---|---|---|
| 内存直接构造 | 代码里 new 一个对象,不入库 | 最快、零耦合,但绕过真实校验和 DB 约束,只适合纯逻辑用例 |
| 数据工厂 / Builder(factory_boy、Faker) | 声明式生成字段、自动带唯一值 | 常规实体造数的主力,天然唯一、易清理,治耦合常用 |
| 调依赖接口造数据链 | 按业务顺序调 API 建完整链(建分类→建课程→上架→可报名) | 最贴近真实、走过真实校验;fixture 里的 factory 多是这一种 |
| DB 直插 / ORM | 绕过接口直接写库 | 快,但绕过校验,数据容易和真实业务状态漂移 |
| 共享 seed | 套件跑前统一灌一份基线数据 | 只适合只读基线;可变数据共用 seed,就是数据耦合的温床 |
选型口诀:可变数据用"工厂 / 依赖接口"现造,带唯一标识、跑完逆序清理;只读基线才用共享 seed。 把业务对象和接口给 AI,它能批量生成工厂和数据链,也能反过来扫现有用例,揪出误用共享可变数据、漏清理的地方。
登录态守四条:每个角色登录一次复用会话,别让每条用例走 UI;token 定时保鲜,否则套件后半段集体踩过期;并行按 worker 分账号,防同账号互踢;注入要放对地方——cookie 用 add_cookies/storage_state,token 存 localStorage 的用 add_init_script。
这里有个高频真坑:别图省事用 set_extra_http_headers 给每个请求塞 Authorization 来"伪登录"。这个头确实会随页面每个请求(含导航)发给后端,但它只骗得过后端鉴权,前端并不知道你登录了——现代 SPA 的登录态由 cookie/localStorage 里的 token 和用户信息驱动,路由守卫看本地没有登录态照样把你踢去登录页,一刷新、一跳转就露馅,表现就是"接口调得通、页面却没登录"。让 AI 改公共登录方法时最容易顺手用头伪登录,审查时盯一眼。
② 其余六类——大多改在用例或 PageObject 层。
| 类型 | 怎么确认 | 怎么修 |
|---|---|---|
| 等待 / 时序(最高发) |
--count、-n auto、慢机器更易红;trace 里动作早于元素就绪或接口返回 |
用自动等待:expect(loc).to_be_visible()、断言最终文本 to_have_text();等接口用 with page.expect_response("**/api/x"): 包住触发动作。禁用固定 time.sleep;别缓存 element handle,detached 就重新定位 |
| 选择器 | 报 strict violation(匹配多个)或匹配 0 个;class 是哈希、用了下标 | 换稳定锚点:首选 get_by_test_id()(让研发补 data-testid),其次 get_by_role();多个时用语义 + 可见性收窄,别用 nth 下标硬凑 |
| 网络 / 第三方 | 红在等某个外部接口,trace 网络里超时/429,重跑常过 | 不依赖真实第三方:page.route 造桩返回固定响应(route.fulfill(json=...));自家接口慢就等响应/等 UI 终态,别 sleep |
| 并发抢资源 | 只在 -n auto 红、单 worker 绿 |
共享资源全部按 worker/用例隔离:数据带唯一标识、独立账号、临时文件用 tmp_path、端口动态分配,不跨用例写同一条数据/文件 |
| 时间 / 时区 / 日期 | 跨天、月底、特定时区才红 | 后端/Python 侧注入时钟,用 freezegun.freeze_time("2026-12-31 23:59:30") 冻结(注意它冻不了浏览器里 JS 的时间,前端跨天逻辑要在页面里 mock 时钟);业务代码别散落 now(),由可注入的时钟提供;断言不写死"今天" |
| 动画 / 遮罩 / iframe / 新窗口 | 元素可见但点不到、点了没反应、句柄丢 | 先等遮罩消失(expect(mask).to_be_hidden())再操作,测试配置开 prefers-reduced-motion;iframe 用 frame_locator() 限定作用域;新窗口用 with context.expect_page() as new_page: 拿句柄 |
跑一遍绿什么都证明不了,四条验收:
| 坑 | 表现 | 卡点 |
|---|---|---|
| 幻觉归因 | 讲个证据里没有的根因 | 强制引用证据行,事实/推测分列 |
| 诱导假修复 | 上来就 sleep/retry/force | 提示词禁止,审查一票否决 |
| 一次绿当成功 | 跑一遍过就宣布修好 | 坚持高压 + 反向验证 |
| 脱离业务乱改 | 不清楚该时序业务上是否允许 | 根因确认和修复取舍由人拍板 |
证据聚合、假设排序、复现设计、修复候选归 AI;是不是这个根因、业务上怎么修才对,永远归人。
分诊跑顺后,让 AI 定期把 flaky 根因标签做一次分布统计——哪类最常犯,哪类就是框架下一步最该长肌肉的地方:等待时序高发就强化 BasePage 自动等待、禁用裸 sleep;登录态成片挂就把保鲜和账号隔离做成默认;数据耦合多就收紧 factory。
于是咬成一个环:整份日志一次分诊,压低"看红灯"的成本;高发根因回到封装里修,减少未来的红灯。
面对一屏红灯,最值钱的用法不是"帮我把这条红的修了",而是:整份日志一次喂给 AI,让它分诊、把 flaky 聚类并直接给根因和修法方向、同时告诉你还缺哪几条证据;人只拍板真缺陷和少数疑难。 判得透的当场修一片,判不透的补料、复现、反向验证;再把每类根因沉淀回框架,存量 flaky 越清越少、同类新坑在公共层就被拦住,套件的稳定性随之收敛。
一句话记住分工:AI 负责大规模地"看"和有依据地"猜",人负责"判"和"拍板"。
如果这篇对你有启发,欢迎转发给那个"CI 一红就重跑、重跑绿了就合入、每天耗在逐条翻日志上"的团队。