3.4 dsh-ci-test-reliability:测试与 flaky 治理
它是什么
dsh-ci-test-reliability 的官方描述:设计、评审并诊断 DeepSeek Harness 的测试与 fixture。
约 9442 字节,另带一份专门的参考资料 ci-flake-diagnosis.md(约 5346 字节)。后者这个名字说明了一切:团队专门为“不稳定测试”写了诊断手册。
多数团队对 flaky 测试的态度是“重跑一下就好了”,dsh 团队的态度是给它写诊断流程、写进技能。这个差别就是这个技能存在的理由。
flaky 测试为什么值得单独治理
一个偶发失败的测试比一个稳定失败的测试危害大得多:
| 稳定失败 | 偶发失败(flaky) | |
|---|---|---|
| 可见性 | 高,立刻发现 | 低,时有时无 |
| 信任侵蚀 | 无(大家都知道它坏) | 严重,团队开始习惯性重跑 |
| 真实 bug 漏网 | 不会 | 会,因为失败被当成噪声 |
| 修复动力 | 有 | 弱,“再跑一次就好了” |
最后一行是最危险的。一旦团队形成“红了就重跑”的条件反射,CI 就失去了守门意义——更糟的是,这个反射会自我强化:重跑越多,失败越被视为噪声;越被视为噪声,越没人去修;越没人修,重跑越多。几周之后,没人说得清 CI 到底是绿的还是只是“跑第二次才绿的”。
稳定失败是明疮,剜掉就行;flaky 是暗伤,它让整套质量信号失真。治理 flaky 本质上是在修复团队的判断能力,而不是修一个测试。
flaky 根因速查表
按一般经验,诊断手册要归类的根因通常离不开下面四类。看到 flaky 先往这几类上靠,比盲目重跑快得多:
| 根因 | 典型表现 | 排查抓手 |
|---|---|---|
| 时间依赖 | 固定 sleep 后断言、依赖“现在”的时刻 |
把相对等待改成条件等待;用注入的时钟 |
| 顺序依赖 | 单独跑过、批量跑挂;换执行顺序就挂 | 让测试不依赖全局执行次序;用随机种子复现 |
| 共享状态 | 测试之间偷偷传数据,上一个改了下一个的环境 | 每个用例独立建库 / 独立目录;禁止模块级可变单例 |
| 外部依赖 | 真连网络、真调时钟、真打外部服务 | 用 mock / fixture 切断外部;对集成测试单独标记 |
| 并发竞态 | 偶发超时、偶发读到旧值 | 缩小临界区;用确定性锁顺序;跑并发多次复现 |
这个表的用法是:拿到一个 flaky,先判断它落在哪一类,再去对应的排查抓手里找复现办法。顺序错了,会在错误的方向上花一下午。
三层覆盖
从“主技能 + 诊断参考”的结构看,这类技能通常分三层:
设计层:
- 测试该测什么(行为而非实现)
- fixture 怎么组织才能避免相互污染
- 并发测试如何隔离
评审层:
- 新测试是否可失败(mutation 思维)
- 是否依赖执行顺序
- 是否有隐藏的时间依赖
诊断层(ci-flake-diagnosis.md):
- 常见 flaky 根因分类
- 复现策略
- 修复优先级判定
三层的顺序有讲究:设计层决定测试“生下来”稳不稳,评审层决定新测试“进门”时过不过关,诊断层决定存量 flaky 怎么清。只做诊断不做设计,就是永远在救火;三层都做,火才会越来越少。
一条最小可复现的玩法
把诊断手册搬回自己项目时,最该保留的是“复现优先”的纪律。一个可落地的做法是给测试加一个循环复现开关:
复现 flaky 的步骤:
1. 固定随机种子(不让顺序每天变)
2. 同一用例连续跑 N 次(N=20~50),记录失败次数
3. 失败率 > 0 但 < 100% → 确认是 flaky,进入诊断表
4. 修复后重复第 2 步,失败率必须降到 0 才算闭合
没有第 4 步的“修复后复跑”,所谓修复只是运气——下一次 CI 它还会红,只是你以为修好了。
三条立即可用的原则
即使不装这个技能,下面三条也值得记住:
原则一:失败必须可复现。 不能稳定复现的失败不许标记为“已修复”。实操上,这意味着修复前先找到复现路径(固定种子、固定顺序、循环跑 N 次),修复后要能演示“以前红的现在不红了”。没有这个闭环,所谓修复只是运气。
原则二:不许无条件重跑。 重跑必须留下记录,让 flaky 率可见。没有重跑计数,你永远不知道自己的 CI 有多少比例是“跑第二次才绿的”——这个数字本身就是团队最该看的健康指标之一。
原则三:新测试先证明会失败。 写测试后故意破坏实现,确认它变红,再恢复。这一步能挡掉大量“永远通过”的假测试:断言写松了、fixture 建错了、路径根本没覆盖到,都会在这一步现形。花三十秒换一个真测试,是测试工程里性价比最高的一笔买卖。
和另外两个技能的关系
dsh-pre-push-checks(3.3 节)负责在推送前跑本地关键检查,其中就包含“相关测试是否通过”;本技能负责让这些测试本身值得信任。一个管“跑了没有”,一个管“跑的结果能不能信”。两件事都做到位,CI 才真正是守门人而不是噪音源。
你要不要装
| 你的情况 | 建议 |
|---|---|
| CI 经常“红了又绿” | 强烈建议,先读诊断手册 |
| 测试偶发超时 | 建议 |
| 项目还很小、无 CI | 不必 |
小结
dsh-ci-test-reliability覆盖测试设计、评审与诊断,约 9442 字节,附带约 5346 字节的 flaky 诊断手册。- flaky 测试比稳定失败更危险,因为它侵蚀团队对 CI 的信任。
- 三层覆盖:设计层、评审层、诊断层。
- 三条原则:失败可复现、禁止无条件重跑、新测试先证明会失败。
