何时使用
- 新功能实现
- Bug 修复
- 重构
- 行为变化
test-driven-development(TDD)是 Superpowers 里最“铁律型”的 Skill 之一。它不是建议,不是经验,不是“有空就做”的最佳实践,而是一个非常明确的工作顺序:
它所防止的,不只是“没写测试”这么简单,而是防止一种更危险的工作习惯:
先写代码,再用测试去证明自己已经写对了。
原文明确指出:如果你没有亲眼看见测试在实现前失败,你就不能确定这个测试真正测到了你以为它在测的东西。
TDD 的流程就是经典的 Red → Green → Refactor,但原文把它执行得非常严:
graph LR
A[RED 写失败测试] --> B{确认失败原因正确?}
B -->|否| A
B -->|是| C[GREEN 写最小实现]
C --> D{确认测试通过且无额外问题?}
D -->|否| C
D -->|是| E[REFACTOR 重构整理]
E --> D
D --> F[下一轮测试]
F --> A
要求很清楚:
这一步不能跳过。 你要确认:
如果测试一开始就 pass:
原文非常强调:
而是:
同样不能跳过。 你要确认:
这一步允许你:
但前提是:
何时使用
何时不用
关键要点
常见错误
| 英文术语 | 中文翻译 | 解释 |
|---|---|---|
| TDD | 测试驱动开发 | 用测试来定义行为,并强制实现按行为收敛。 |
| RED | 红灯阶段 | 先写失败测试,证明测试确实测得到目标行为。 |
| GREEN | 绿灯阶段 | 写最小实现让测试通过。 |
| REFACTOR | 重构阶段 | 在测试保持通过的前提下清理代码结构。 |
| Iron Law | 铁律 | 没有失败测试,就不允许写生产代码。 |
| Rationalization | 自我合理化 | 用“这次特殊”“太简单了”等借口跳过 TDD。 |
| 错误行为 | 为什么是错的 | 正确做法 |
|---|---|---|
| “我先写出来,再补测试” | 测试会被实现结果反向影响 | 先写测试,再写实现 |
| 测试一开始就 pass | 证明不了它真的测到了行为 | 回去修测试,直到正确 fail |
| 把已有实现保留作“参考” | 本质上还是 tests-after | 删除实现,按测试重新写 |
| 手工测过了就不写测试 | 手工验证不可复用、不可回归 | 让 bug/行为进入自动测试 |
| 测试太难写,就先略过 | 往往说明设计本身太复杂 | 简化接口或重新设计 |
这份 Skill 的语气非常强硬,甚至近乎“宗教化”,比如:
这种强度不是为了形式感,而是为了防止开发者滑回最常见的模式:
先写代码,再想办法给它找测试。
因为一旦进入这种顺序,测试很容易变成:
原文反复强调顺序,是在保护测试的“约束力”。
程序员在真实工作中很容易说:
这类说法的共同点是: 它们看起来节省时间,但通常会把时间花到后面更贵的地方:
TDD 并不是让你慢,而是把时间前置到“定义行为”上,减少后面的修补和不确定性。
错误做法:
正确做法:
错误做法:
正确做法:
错误做法:
正确做法:
❌ 错误:先写实现代码,再补测试✅ 正确:先写失败测试,运行确认失败,再写最小实现❌ 错误:直接修改代码让它看起来能工作✅ 正确:先写测试复现 Bug,确认测试失败,再修复# RED 阶段:写失败测试npm test -- --testNamePattern="描述测试名称"
# 验证测试失败# expected error, got undefined
# GREEN 阶段:写最小实现# 让测试通过
# REFACTOR 阶段:重构# 保持测试通过的前提下优化代码| 坑 | 表现 | 解决 |
|---|---|---|
| 先写实现再补测试 | 测试被实现反向影响 | 删除实现,从测试重新开始 |
| 测试直接通过 | 没验证测试真测到行为 | 确认测试正确 fail |
| ”这次例外” | 跳过 TDD 流程 | 没有任何例外 |
using-superpowers,用于决定当前是否该进入 TDD;writing-plans,用于在复杂实现前先把计划写清楚。verification-before-completion,因为 TDD 并不替代最终验证。systematic-debugging,用于当 bug 尚未被准确理解时,先定位问题,再写失败测试复现。这份附属文档把很多“看起来像在写测试,其实没有真正验证行为”的问题讲得非常透。
它重点批评了几类常见反模式:
比如断言一个 mock sidebar 被渲染出来,这实际上只证明 mock 存在,不证明真实组件行为正确。
比如为了测试方便,在生产类里加 destroy() 这种只给测试用的方法。原文认为这会污染生产 API。
为了“安全”或“省事”把高层依赖都 mock 掉,结果把测试真正依赖的副作用也一起抹掉了。
只 mock 你当前测试用到的字段,而不按真实 API 结构模拟,最后造成“测试通过、集成失败”。
这份文档的真正价值在于提醒你:
测试不是为了让 CI 变绿,而是为了验证真实系统行为。
所以 mock 是工具,不是主角;测试结构也必须服务于真实行为验证。
查看源文件: GitHub原始文件