方法

TDD

测试驱动开发

先写测试。看它失败。写让它通过的最简代码。重构。重复。

最近审阅: 2026-05-24 审阅人Kevin Riedl wiki ↗

TDD 是一种纪律,不是方法论。循环是:红(写一个会失败的测试)、绿(写让它通过的最简代码)、Refactor(在不破坏测试的前提下清理)。照字面做,它产出高测试覆盖率的代码,以及一种对抗过度工程的强制力。这种纪律只有在那些测试每次变更都跑时才会有回报,所以 TDD 和 CI/CD 是兄弟,不是分开的两件事。

多数团队嘴上做 TDD、实际却不做的原因:当下先写测试感觉更慢。复利的回报(Refactor 安全、回归覆盖、朝更小单元的设计压力)要数月之后才显现。到那时,团队早已停止先写测试,并说服自己它从没起过作用。

TDD 在哪里赚回成本、在哪里只是表演,举个实际例子:一个支付对账模块有棘手的边缘情况(部分退款、货币舍入、重试)。先写那个会失败的测试,迫使你在代码存在之前就陈述期望行为,而当六个月后有人「简化」舍入时,那套套件抓住了回归。那是 TDD 在为自己买单。再对照一个你两周后就要删掉的一次性数据导入脚本:在那里先写测试纯属开销。诚实的规则是对逻辑密集、出错代价高的代码做 TDD,其余的不做。

最常见的错误是把覆盖率当成一个目标。追 90%,团队就会为 Getter 和 Setter 写测试去凑那个数字,却跳过真正 Bug 所在的集成测试。覆盖率是一个有用的诊断、一个糟糕的目标;它是个会被刷分的指标。Wavect 在它有回报的地方用 TDD:任何和钱相关的东西做集成测试,任何面向客户的东西做契约测试,产品需要读得懂的地方做 BDD 式验收测试,不平凡的逻辑做单元测试。我们把难的部分测好,而不是把所有部分平均地测,并且把它当作一个健康的 Agile 循环里的一项实践,而不是一个要打的勾。

// FAQ

常见问题

因为当下感觉更慢。红 / 绿 / Refactor 循环要数月之后才显出复利收益,多数团队还没看到收益就放弃了,然后自我说服「反正没什么不同」。坚持下来的团队,Refactor 安全感与回归保护是真实可量化的。
不是。把覆盖率当目标,团队会写测试覆盖 Getter / Setter、写永远会通过的废测试,数字漂亮但保护力为零。值得测试的是钱相关的集成、面向客户的契约、复杂逻辑分支。覆盖率是结果指标,不是目标指标。
原型与 Spike:目标是回答「这件事可行吗」,写完就要扔的代码不值得做先写测试。一旦确认方向、决定保留代码,再补关键路径的测试。把 TDD 用在 Spike 上,是在为「将要被删掉的代码」交保护费。