目标
当红色构建被习惯性地重跑到变绿,测试套件就不再是证据而只是噪音。连跑三遍、统计失败方差、用种子加乱序复现,能把“感觉这测试偶尔挂”变成一份按优先级排名、有责任人、有过期时间的隔离清单,让真正的回归不再藏进十个已知不稳定测试的阴影里。
步骤要点
- 连续跑三遍套件并各存一份失败列表,先 diff 区分反复失败与偶发失败。
- 合并三份列表做 uniq -c 统计:计数为 3 的是真坏的测试要修,计数 1-2 的就是不稳定测试,按计数排优先级。
- 用 –sequence.shuffle 加不同 seed 复现单个不稳定测试,证明它依赖执行顺序或时序,而不是瞎猜。
- 隔离被证实的惯犯:显式配置排除或 @flaky 标记,每条写清 owner、expiry 与 reason,绝不静默删除。
- 单独跑隔离车道形成周报,某条测试连续两周稳定通过时凭绿色运行记录毕业回主套件。
排错提示
本地无法复现的多半是 CI 独有的共享状态或资源受限,抓日志与计时信息或在本地跑同一容器镜像复现环境;重跑到绿已是习惯就先把重试显式化,需要重试才过的构建记为失败并统计每周重试数,用指标把习惯变成修根因的压力;隔离清单只增不减就给每条加过期时间并路由到责任人,没有衰减机制的清单只是杂物抽屉。
适用边界
三遍运行只证明观测到的种子与顺序下的间歇性,更深的时序 bug 需要压力循环或注入延迟;隔离会把信号挡在主套件外,周报必须如实汇报隔离车道的通过率。
代码示例
# Three runs, three failure lists
for i in 1 2 3; do
npx vitest run --reporter=json > run-$i.json || true
done
# Which tests fail sometimes, and which always?
cat fail-1.txt fail-2.txt fail-3.txt | sort | uniq -c
# 3 checkout/applies-coupon -> genuinely broken
# 1 search/debounces-input -> flaky (order/time dependent)
# 2 auth/refresh-token -> flaky (clock skew)
# Reproduce one offender deterministically
npx vitest run --sequence.shuffle --sequence.seed=42