测试即门禁
用途:让测试成为交付的强制条件,而不是可选的自检
核心命题
「核心命题」小节链接测试的价值不在“跑过了”,而在“改坏会失败”。 只有前者时,测试是文档;做到后者,测试才是门禁。
对 Agent 交付尤其关键:Agent 可以写测试,也可以写“永远通过”的测试。
门禁对测试的四项要求
「门禁对测试的四项要求」小节链接| 要求 | 检查方式 | 失败归类 |
|---|---|---|
| 必须存在 | 新增/修改的公开行为是否有对应测试文件与用例 | UNVERIFIED |
| 必须运行 | 执行日志、用例计数 > 0、耗时合理 | UNVERIFIED |
| 必须有效 | 断言数量下限、变异杀伤率、破坏性验证记录 | UNVERIFIED / FAIL |
| 不得被削弱 | 断言删除/放宽、skip、阈值下调、mock 掉被测对象本身 | FAIL |
第四项是“裁判保护”:把测试与配置视为受保护资产,变更需人工确认。
断言质量的可量化信号
「断言质量的可量化信号」小节链接- 断言密度:每用例平均断言数,过低说明只跑不验。
- 变异杀伤率(mutation score):注入代码变异后测试能否失败,是“测试有效性”最直接的量化。工具如 PIT(Java)、mutmut/cosmic-ray(Python)、Stryker(JS/TS)。
- 覆盖率作为下限而非目标:只用于发现“完全没被测到的分支”,不能作为质量证明(高覆盖率 + 空断言是常见组合)。
- 失败信息可读性:断言消息是否说明期望与实际,影响排障效率。
先失败后通过(缺陷修复的硬要求)
「先失败后通过(缺陷修复的硬要求)」小节链接修复类任务必须提供复现用例:在修复前运行失败,修复后通过。没有这一步,无法区分“修好了”与“测试条件太松”。
门禁可自动化检查:要求提交包含“复现用例 + 失败证据(修复前运行记录)”。
Mock 的边界
「Mock 的边界」小节链接| 可以 mock | 不可以 mock |
|---|---|
| 外部 HTTP、第三方 SDK、时钟、随机数 | 被测对象自身的关键逻辑 |
| 慢且不参与本次断言的依赖 | 数据库事务语义(若被测行为依赖它) |
用内存假实现替代真实依赖做集成测试是常见陷阱:生产用的是真组件,测试通过不代表行为正确。分层策略:单元测试用替身,集成测试用真实组件(Testcontainers 类方案),端到端用权威环境。
测试稳定性
「测试稳定性」小节链接不稳定的测试(flaky)会摧毁门禁公信力。处理原则:
- 隔离并重跑识别 flaky 用例,进入修复队列并设 SLA。
- 禁止用“重试到通过”掩盖问题;重试次数与结果必须留痕。
- 时间、并发、外部依赖顺序是三大常见根因,优先从测试设计解决。
常见误区
「常见误区」小节链接| 误区 | 修正 |
|---|---|
| 覆盖率达标即质量达标 | 配合断言密度与变异杀伤率 |
| Agent 自己写测试自己判定 | 裁判保护:测试变更需人工确认 |
| flaky 用例直接 skip | 计入未验证并限期修复 |
| 集成测试全 mock | 关键路径用真实组件 |
| 只看用例数量 | 数量不证明有效性 |
延伸阅读
「延伸阅读」小节链接- 变异测试公开文献与 PIT / Stryker / mutmut 文档
- Testcontainers 官方文档(真实依赖的集成测试)
- 本站:完成的证据层级、fail-closed 门禁设计