Superpowers TDD实践:一次跑通完整的RED-GREEN-REFACTOR循环
2026/8/28 12:02:37 网站建设 项目流程

Superpowers TDD实践:一次跑通完整的RED-GREEN-REFACTOR循环

【免费下载链接】superpowersAn agentic skills framework & software development methodology that works.项目地址: https://gitcode.com/GitHub_Trending/su/superpowers

修bug最怕的就是:这一下改好了,那一下又改出个新的。测试驱动开发(TDD)就是为防这件事而生的。本文拿 Superpowers 项目的真实约定,带你完整走一遍 RED-GREEN-REFACTOR 循环:怎么写一个"预期失败"的测试、怎么写刚好通过的代码、怎么安全地改代码;再附上三类常见场景、常见 TDD 误区,以及一份 TDD 新手教程级的动手指南。

什么是RED-GREEN-REFACTOR:一句话看懂TDD的铁律

一句话版本:先写测试,看着它失败,再写刚好让它通过的代码,最后在不改变行为的前提下改代码。三步走完,就是一个 TDD 循环:

  • RED — 写失败的测试:把功能该有的行为先说清楚,此时功能还没实现,测试必须失败
  • GREEN — 写最小实现:不优化、不考虑扩展性,只求把测试变绿
  • REFACTOR — 改结构,保行为:测试是安全网,此时整理代码,行为一点不能变

Superpowers 对此定了条铁律:没有失败的测试,就不要编写生产代码。写不出测试,说明你还没想清楚要做什么。

一次完整TDD循环走查:拿"金额校验"举例

我们来完整过一遍。假设需求是:下单金额不允许为负数。

第一步(RED):写一个必须失败的测试

先用测试语言把期望行为描述出来:

test('rejects a negative amount', () => { const result = checkAmount(-10); expect(result.error).toBe('Amount cannot be negative'); });

按项目约定,测试文件命名为test-<skill-name>.sh,放在测试脚本目录下。跑一次:

npm test path/to/test.test.ts

它必须失败——因为checkAmount还不存在。如果不失败,说明测试本身有问题,先修测试。

第二步(GREEN):写刚好通过的代码

只写让测试通过的最少代码,多一行都不写:

function checkAmount(value: number) { if (value < 0) { return { error: 'Amount cannot be negative' }; } return { ok: true }; }

再跑一次npm test path/to/test.test.ts,这次变绿 🟢。注意:测试没要求"金额上限",这里就别加,那叫过度设计。

第三步(REFACTOR):改结构,保行为

有了测试垫底,现在改代码是安全的。比如把校验规则抽成配置,方便以后加新规则:

const rules = [ { test: (v: number) => v < 0, message: 'Amount cannot be negative' }, ]; function checkAmount(value: number) { for (const rule of rules) { if (rule.test(value)) return { error: rule.message }; } return { ok: true }; }

跑一遍测试,必须全部保持绿色。一旦变红,立刻停下回滚,不许"顺手"继续改。

三类常见场景:新功能、修bug、重构

同一个循环,场景不同只是起点不同:

  • 开发新功能:从"期望行为"出发。先把想调用的 API 写成测试,断言写得出来,设计就基本成型了
  • 修bug:第一步是写一个能复现 bug 的测试(RED)。举个例子:如果0被误判成非法金额,就先写一条"0 是合法金额"的测试,确认它失败,再修判断逻辑让它变绿,最后整理代码。复现测试写不出来,通常说明你还没看懂这个 bug
  • 重构:前提是测试本来就在通过。改命名、抽函数、消重复,因为行为不变,所以每一步都是"安全"的

容易踩的坑:测试怎么写得出来、又干净

下面几问几答,是实际操作时最常遇到的情况:

  • 不知道怎么测?先把你期望的 API 和断言语句写出来;实在写不出来,找同事聊——往往会发现是设计本身要改
  • 测试复杂到读不懂?复杂的测试常常是复杂设计的信号,回去简化设计
  • 是不是所有依赖都得模拟?优先用依赖注入降低耦合,模拟只在必要时用;测试尽量走真实代码
  • 铺垫代码太厚?抽成辅助函数;抽完还厚,说明设计已经过大了
  • 测试名起得含糊?名字要描述行为(test('test1')这种是不允许的),一个测试只验证一件事,名字里出现"和"就该拆
  • 测到了实现细节?只关注"它做了什么",不关注"它怎么做的"——测行为,不测代码结构

在Superpowers中三步开始TDD实践

先克隆仓库:

git clone https://gitcode.com/GitHub_Trending/su/superpowers

然后读一遍 TDD技能文档,把三个阶段的循环要求和测试质量原则弄清楚。最后挑一个小功能,完整走一遍 RED-GREEN-REFACTOR,再跑测试脚本确认:

cd tests/claude-code ./run-skill-tests.sh

其中 run-skill-tests.sh 是批量执行技能测试的入口;写测试时可以直接复用 test-helpers.sh 里的公共辅助函数;想看现有案例,参考 test-subagent-driven-development.sh。

提交前自查清单

  • 每个新函数/方法都有对应的测试
  • 实现之前亲眼看到过测试失败(而不是想当然认为它会失败)
  • 失败的原因是"功能缺失",而不是拼写、语法错误
  • 写的是刚好能通过测试的最少代码
  • 所有测试通过,输出干净、无错误和警告
  • 测试尽量使用真实代码,模拟只出现在必要时
  • 边缘情况和错误处理都已覆盖

有一条勾不上,就说明流程跑偏了——推倒重来比事后修补更快。TDD 不是形式主义的步骤,而是"先想清楚再动手"的思维方式;下次动手写生产代码前,先问一句:那个失败的测试,写好了吗?

【免费下载链接】superpowersAn agentic skills framework & software development methodology that works.项目地址: https://gitcode.com/GitHub_Trending/su/superpowers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询