测试驱动开发(TDD)

先用测试定义行为,再用最小实现满足它,并在测试保护下持续重构的开发方法。

#type / concept #status / evergreen #tech / dev / test

[!info] related notes

测试驱动开发(TDD)

一句话定义

TDD 不是“多写测试”,而是先写一个失败的测试来定义下一个行为,再写最小实现让它通过,最后在测试保护下重构设计。

它到底驱动什么

TDD 驱动的重点不是测试数量,而是设计过程本身。

  • 先写测试,会先逼你想清楚接口、调用方式和外部可观察行为
  • 最小实现会限制你不要顺手把未来需求提前写进去
  • 重构步骤会把“先跑通”升级成“结构也干净”

所以 TDD 更接近一种设计和实现的微循环,而不是 QA 工作前移。

它不是什么

  • 不是“写完代码后顺手补测试”
  • 不是“为了覆盖率把 trivial code 也测一遍”
  • 不是“只做 Red-Green,不做 Refactor”
  • 不是“把所有测试都叫 TDD”

如果代码已经有自动化测试保护,那叫 自测试代码(Self-Testing Code);TDD 是达到这类代码的一种强方法,但不是唯一方法。

TDD 真正解决的问题

1. 快速反馈

你不需要等到联调、提测或线上故障才知道偏离了需求,小测试会在几十毫秒到几秒内给出信号。

2. 改善设计

因为思考顺序从“怎么用它”开始,而不是“我想怎么实现”,接口通常会更稳定,依赖也更容易被隔离。

3. 支持安全重构

TDD 的第三步不是装饰,而是核心。只有在测试持续变绿的前提下重构,代码才能同时保持可用和可维护。

4. 回归保护

成熟团队遇到 bug 时,第一反应通常不是直接修,而是先写一个能稳定复现 bug 的测试,再修实现,让 bug 不会轻易回来。

它最适合驱动什么

  • 业务规则、计费、权限、状态流转
  • 解析、转换、校验逻辑
  • 纯函数、领域服务、核心模块
  • 历史 bug 的回归保护
  • 对外部系统的契约边界

它不适合一上来就重度使用的场景

  • 强视觉、强交互、还在快速试样的 UI 探索阶段
  • 一次性脚本和临时 spike
  • 需求与接口还明显摇摆的原型阶段

但即使这些场景不严格按 TDD 开始,一旦需求稳定,关键路径仍然应该补成 自测试代码

在 AI 时代为什么更重要

AI 很会写“像对的代码”,但不一定真的对。

这让 TDD 在 AI 时代的角色从开发习惯升级成:

  • 可执行规格
  • 局部任务边界
  • 自动验收器
  • 重构安全网

也就是说,TDD 不只是帮助人类收敛设计,也是在帮助 agent 不要乱写、跳步和幻觉式完成任务。

详见 AI 编码时代的 TDD

最短记忆方式

TDD = 先用测试定义行为,再用最小实现满足它,最后在测试保护下重构。

参考资料

创建于 2025/1/1 更新于 2026/5/27