“这个用例又挂了?应该不是真 bug 吧?”——当这句话在团队里成为常态,测试系统的公信力就死了。Flaky 用例的危害不是"多跑几次",而是训练出"红了也不信"的团队文化。这篇讲 flaky 治理的完整闭环:识别、量化、隔离、根因、消灭。
一、先定义:什么是 flaky(别把真 bug 当 flaky)
1 | Flaky 判定标准(三条同时满足): |
关键区分:flaky 是"测试系统的噪音",竞态 bug 是"产品的缺陷"。把竞态 bug 当 flaky 隔离掉,等于让产品缺陷隐身——判定时先问"这个不稳定是不是产品该有的行为"。
二、量化:给 flaky 建监控(没有数据就没有治理)
1. flaky 识别机制(自动化,不靠人肉回忆)
1 | # 每次 run 记录用例结果序列,滑动窗口判定 |
2. flaky 率看板(团队级 + 用例级)
1 | 团队 flaky 率 = 近 7 天被判定 flaky 的用例数 / 总用例数 |
flaky 率是"测试系统健康度"的北极星指标——它比通过率更能反映"测试结果可信不可信"。
三、隔离区:显式承认不稳定,限期治理
flaky 用例不能"带着红继续跑"(污染门禁),也不能"直接删"(假装没发生)。隔离区机制:
1 | 进入隔离区(自动): |
隔离区的本质是"公开的不稳定清单"——它把"这个用例爱挂"从口口相传变成带 owner、带期限、带数据的工单。
四、根因分类与典型解法(按占比排序)
治理要按根因下对药。我们半年的数据(214 个 flaky 用例的根因分布):
| 根因 | 占比 | 典型解法 |
|---|---|---|
| 时序/等待不足 | 38% | 固定 sleep → 条件等待;"动画结束"类加视图静止等待(iOS 见 WDA 篇);并发场景加 barrier 同步 |
| 数据耦合 | 27% | 用例间共享数据 → 命名空间隔离(数据工厂那篇);全局列表断言"精确数量" → 断言"包含";环境残留 → teardown 强制清理 + 租约回收 |
| 环境抖动 | 15% | 网络/设备/时钟 → 环境指纹对账 + 设备健康巡检(degraded 降权);共享 staging 被人工操作 → 测试专用环境 |
| 依赖服务状态 | 10% | 依赖的数据状态 → Mock 化(Playwright route / Mock WS);依赖限流 → 测试账号走白名单 |
| 真实竞态 bug | 8% | 修产品代码,不是修用例——这类"flaky"恰恰是自动化的高价值产出 |
| 断言过严 | 2% | 断言"精确文案"(含动态数字/时间)→ 断言结构不断言字面值 |
两个反直觉的结论:
- "加 sleep"是 flaky 的常见"解法",也是最大根因——sleep 治标(掩盖时序)且制造新 flaky(sleep 不够还是挂)。CI lint 规则:
time.sleep在测试代码里直接告警,强制走条件等待; - 8% 的"flaky"是真 bug——治理流程的副产品是抓到竞态缺陷,flaky 治理做得越认真,产品越干净。
五、从"修用例"到"修系统":隔离区超 5% 时
单个 flaky 修用例,系统性 flaky 修系统。隔离区占比持续 > 5% 说明基础设施有问题,按这个顺序排查:
1 | 1. 数据层:隔离是否彻底?(命名空间/租约/teardown 三件套) |
修系统的收益是指数级的——数据隔离补全后,我们 27% 的数据耦合类 flaky 一次性清零,而不是修 58 个用例。
六、小结
Flaky 治理五步闭环:定义(区分噪音和竞态 bug)、量化(flaky 率 + 用例 flaky 分)、隔离(公开清单 + owner + 期限)、根因(六类,时序和数据占 2/3)、修系统(占比超 5% 修基建不修用例)。终极标准只有一个:团队看到红的时候,第一反应是"出事了"而不是"又挂了"——这个反应恢复之日,才是 flaky 真正治理完成之时。