AI时代,Agent比人类更需要测试驱动开发(TDD)。Agent缺乏手动验证手段,只能靠自我推理或自动化测试。TDD强制先写失败测试再编码,引入客观验证。铁律规定无失败测试不得写生产代码,违反则删除重写。红-绿-重构循环确保每一步可验证,避免Agent自我合理化错误。
上一篇我们聊了 Subagent-Driven Development 的执行与审核机制。但说到底,审核能发现问题,却无法从源头预防问题。Superpowers 的做法是从源头就掐住问题的脖子——强制 AI Agent 必须先写测试,再写实现代码,从而确保测试驱动开发(TDD)真正落地。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
别误会,这不是什么新概念——测试驱动开发(TDD)已经存在 20 多年了。但 Superpowers 对 TDD 的理解和处理方式,和传统认知截然不同:它不是在讲"TDD 是一种好的开发实践",而是在说"对 AI Agent 而言,TDD 是唯一能证明代码正确的方式"。这个出发点,让一切都有了不一样的意义。
人类开发者不做 TDD,至少还有几层兜底:可以手动测试、可以用 IDE 调试器、可以运行程序看输出、可以凭经验判断边界条件。但 AI Agent 没有这些——它不能"运行程序看看对不对"(除非你配了自动化执行环境),它的"验证"手段只有两个:
如果没有测试,AI Agent 唯一的验证途径就是自我推理。而模型最擅长的事情之一,恰恰是"合理化解释自己的错误"——你让它 review 自己写的代码,它大概率会说"没问题,一切正常"。这正是测试驱动开发要解决的核心问题。
TDD 正是打破这个循环的关键:先写测试,测试失败了,再写代码让它通过。这个过程引入了客观的、可验证的中间步骤,完全不依赖 AI Agent 的自我判断。
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
这是 TDD skill 里的铁律——全大写、无条件、没有例外。违反了怎么办?答案很直接:
Write code before the test Delete it. Start over.No exceptions:- Don't keep it as "reference"- Don't "adapt" it while writing tests- Don't look at it- Delete means deleteImplement fresh from tests. Period.
注意,这里说的不是"测试没写好需要修改"——而是如果你先写了生产代码再补测试,代码直接删掉,没有商量余地。为什么这么极端?
因为一旦代码已经存在,你写的测试会无意识地去"验证现有行为",而不是"定义期望行为"。你会看着代码写断言,测试变成了对实现的确认,而不是对需求的规约。这个心理陷阱,人类会犯,AI Agent 更会犯。
TDD 的核心循环有三步,每一步都带有强制验证点:
RED → Verify RED → GREEN → Verify GREEN → REFACTOR → (stay green) → next RED
写一个最小化的测试,描述你期望的行为:
test('retries failed operations 3 times', async () => {let attempts = 0;const operation = () => {attempts++;if (attempts < 3) throw new Error('fail');return 'success';};const result = await retryOperation(operation);expect(result).toBe('success');expect(attempts).toBe(3);});
一个测试只测一个行为。测试的名字要能让人一眼看出"什么场景下预期什么结果"。
对比一下反面教材:
test('retry works', async () => {const mock = jest.fn().mockRejectedValueOnce(new Error()).mockRejectedValueOnce(new Error()).mockResolvedValueOnce('success');await retryOperation(mock);expect(mock).toHa veBeenCalledTimes(3);});
问题很明显:名字模糊——"retry works"说了等于没说;而且测的是 mock 的调用次数,而不是真实的行为。
MANDATORY. Never skip.
运行测试,确认它:
如果测试直接通过了怎么办?说明你在测试已有行为——要么功能已经存在,要么测试写错了。修改测试,而不是跳过验证。
这一步的意义在于:证明测试确实能检测到"功能缺失"。如果你跳过这一步直接写实现,你永远不知道这个测试到底有没有在检测什么东西。
写刚好能让测试通过的代码,不多不少:
async function retryOperation
对比一下过度实现的样子:
async function retryOperation
关键原则:不要添加测试没要求的功能,不要重构其他代码,不要做任何"超越测试"的优化。
运行测试,确认:
Test fails Fix code, not test.Other tests fail Fix now.
只有在 GREEN 之后才能进行重构:
约束很明确:重构不能改变行为——测试必须始终保持绿色。
回到起点,写下一条测试。整个循环是增量式的——每次只前进一小步,每一步都有据可查。
Superpowers 用了很大篇幅来解释"为什么不能先写代码后补测试"。这些不是教条式的论证,而是针对 AI Agent 最容易犯的错误而设计的。
Tests written after code pass immediately. Passing immediately proves nothing:- Might test wrong thing- Might test implementation, not beha vior- Might miss edge cases you forgot- You never saw it catch the bugTest-first forces you to see the test fail, proving it actually tests something.
这一点对 AI Agent 尤其致命——Agent 补的测试几乎一定是基于它已经写好的实现。它不会故意写出不通过的测试,这就完全失去了 TDD 的意义。
Manual testing is ad-hoc. You think you tested everything but:- No record of what you tested- Can't re-run when code changes- Easy to forget cases under pressure- "It worked when I tried it" ≠ comprehensive
Sunk cost fallacy. The time is already gone. Your choice now:- Delete and rewrite with TDD (X more hours, high confidence)- Keep it and add tests after (30 min, low confidence, likely bugs)The "waste" is keeping code you can't trust.
TDD IS pragmatic:- Finds bugs before commit (faster than debugging after)- Prevents regressions (tests catch breaks immediately)- Documents beha vior (tests show how to use code)- Enables refactoring (change freely, tests catch breaks)"Pragmatic" shortcuts = debugging in production = slower.
这是 Superpowers 的 Rationalization Prevention 机制在 TDD 领域的具体应用——提前把所有可能的借口摆到桌面上,一一击破:
| 借口 | 现实 |
|---|---|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests passing immediately prove nothing. |
| "Tests after achieve same goals" | Tests-after = "what does this do" Tests-first = "what should this do" |
| "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. |
| "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. |
| "Keep as reference, write tests first" | You'll adapt it. That's testing after. Delete means delete. |
| "Need to explore first" | Fine. Throw away exploration, start with TDD. |
| "Test hard = design unclear" | Listen to test. Hard to test = hard to use. |
| "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. |
| "Manual test faster" | Manual doesn't prove edge cases. You'll re-test every change. |
| "Existing code has no tests" | You're improving it. Add tests for existing code. |
注意第 7 条"Need to explore first"——Superpowers 允许探索性编码(spike),但要求探索完成后把所有代码删掉,从 TDD 重新开始。探索的目的是理解问题,而不是产出代码。
- Code before test- Test after implementation- Test passes immediately- Can't explain why test failed- Tests added "later"- Rationalizing "just this once"- "I already manually tested it"- "Tests after achieve the same purpose"- "It's about spirit not ritual"- "Keep as reference" or "adapt existing code"- "Already spent X hours, deleting is wasteful"- "TDD is dogmatic, I'm being pragmatic"- "This is different because..."All of these mean: Delete code. Start over with TDD.
最后一条 "This is different because..." 是最狡猾的——AI Agent 总能找到"这次情况特殊"的理由。Superpowers 的回答很简单:没有"特殊情况"。
| 维度 | 好的测试 | 坏的测试 |
|---|---|---|
| Minimal | 只测一件事。名字里有"and"?拆开。 | test('validates email and domain and whitespace') |
| Clear | 名字描述行为 | test('test1') |
| Shows intent | 展示期望的 API 用法 | 让人看不出代码应该怎么用 |
| Real code | 用真实代码(mock 只在不可避免时用) | 到处 mock |
一个关键原则:测试应该展示 API 的理想用法。如果你的测试代码写得很丑陋、很复杂,那说明 API 设计本身有问题。
Test hard = design unclear. Listen to test. Hard to test = hard to use.
Bug 修复特别适合 TDD——先写测试重现 bug,再修复,一劳永逸。这是测试驱动开发在缺陷管理中的典型应用。
假设有个 bug:空邮箱被接受了。
RED(重现 bug):
test('rejects empty email', async () => {const result = await submitForm({ email: '' });expect(result.error).toBe('Email required');});
Verify RED:
$ npm testFAIL: expected 'Email required', got undefined
测试失败了,证明 bug 确实存在。
GREEN(最小修复):
function submitForm(data: FormData) {if (!data.email.trim()) {return { error: 'Email required' };}// ...}
Verify GREEN:
$ npm testPASS
REFACTOR:如果有多个字段需要类似验证,提取验证逻辑。
这个流程的好处在于:修完 bug 后,这个测试永远留在测试套件里。如果以后有人改动了相关代码导致 bug 回归,测试会立即捕获。
Bug found Write failing test reproducing it. Follow TDD cycle. Test proves fix and prevents regression.Never fix bugs without a test.
| 问题 | 解法 |
|---|---|
| 不知道怎么测 | 先写理想的 API 调用方式。先写断言。如果还是不行,去问你的 human partner。 |
| 测试太复杂 | 说明设计太复杂了。简化接口。 |
| 必须 mock 所有东西 | 代码耦合太紧。用依赖注入来解耦。 |
| 测试 setup 太大 | 提取 helper。如果仍然复杂,那就说明设计需要简化。 |
核心理念:测试困难是设计问题的症状,而不是 TDD 方法论的问题。如果测试很难写,不是"TDD 不适合这个场景"——而是"代码设计需要改进"。
每次任务完成前的自查清单:
Before marking work complete:- [ ] Every new function/method has a test- [ ] Watched each test fail before implementing- [ ] Each test failed for expected reason (feature missing, not typo)- [ ] Wrote minimal code to pass each test- [ ] All tests pass- [ ] Output pristine (no errors, warnings)- [ ] Tests use real code (mocks only if una voidable)- [ ] Edge cases and errors coveredCan't check all boxes You skipped TDD. Start over.
在 Subagent-Driven Development 流程中,TDD 在 Implementer subagent 环节发挥作用:
Coordinator 分派 task│▼Implementer subagent 开始执行│├── RED: 写失败测试├── Verify RED: 运行确认失败├── GREEN: 最小实现├── Verify GREEN: 运行确认通过├── REFACTOR: 清理└── Commit│▼Spec Reviewer: 实现匹配 spec 吗?│▼Code Quality Reviewer: 代码质量如何?
Implementer 内部用 TDD 保证自己写的代码是正确的。Reviewer 从外部视角验证它是否满足 spec 和质量标准。内部保障(TDD)+ 外部审核(Review)= 双重质量闭环。
TDD 对人类来说是"更好的实践"。但对 AI Agent 而言,TDD 几乎是"唯一可靠的验证手段":
| 验证方式 | 人类 | AI Agent |
|---|---|---|
| 手动运行程序 | 随时可做 | 需要特殊环境配置 |
| IDE 调试器 | 设断点、看变量 | 不可用 |
| 直觉/经验判断 | 有一定可靠性 | 模型会 rationalize |
| 自动化测试 | 可选 | 唯一客观手段 |
| 自我 review | 有一定效果 | 严重偏向自己的代码 |
这就是为什么 Superpowers 把 TDD 从"推荐实践"升级为"铁律"——不是因为教条,而是因为 AI Agent 没有其他可靠的质量保障手段。
在你的 CLAUDE.md 或 system prompt 里加上类似的约束:
## TDD 铁律所有新功能和 bug 修复必须遵循 RED-GREEN-REFACTOR:1. 先写一个失败的测试2. 运行测试确认它失败了(不是报错,是失败)3. 写最少的代码让测试通过4. 运行测试确认通过5. 需要的话清理代码违反(先写代码再补测试)→ 删除代码从测试重新开始。
大多数 AI Agent 愿意先写测试——但它们经常跳过"运行测试确认失败"这一步。这一步是 TDD 的灵魂:如果你没看到测试失败,你就不知道它到底在检测什么。
If you didn't watch the test fail, you don't know if it tests the right thing.
AI Agent 会找各种理由跳过 TDD。提前把这些理由列出来并标记为"这不是合理的跳过理由"——这就是 Rationalization Prevention 的力量。
Superpowers 对 TDD 的处理揭示了一个深层洞察:AI Agent 需要 TDD 不是因为"好的开发习惯",而是因为自动化测试是它唯一的客观质量验证手段。
没有 TDD 的 AI Agent 只能靠自我推理来判断代码对不对——而这恰恰是最不可靠的方式。TDD 提供了客观的、可重复的、不依赖自我判断的验证路径。
下一篇是本系列的终章:当你想创建自己的 Skill(行为塑造代码)时,怎么用"压力测试"来确保它真的能约束 AI Agent——Writing Skills 的 TDD。
不需要 Superpowers。把下面这段加到你的 CLAUDE.md 里:
## TDD 铁律NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST.违反后果:- 测试之前写了代码?删掉,从头来。- 不要保留"参考"、不要"适配"、不要看它。删除就是删除。Red-Green-Refactor 循环:1. RED:写一个最小的失败测试,跑一遍确认它失败2. GREEN:写最少的代码让测试通过,跑一遍确认通过3. REFACTOR:测试通过后清理代码4. 每一步都要实际执行命令看输出——"我觉得会通过"不算。禁止用语:should pass, probably works, seems right, I tested it manually
本文素材来源:obra/superpowers/skills/test-driven-development/SKILL.md
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述