2026年Superpowers - 12 没有失败测试,就没有生产代码:从 Superpowers 看“铁律级”测试驱动开发

Superpowers - 12 没有失败测试,就没有生产代码:从 Superpowers 看“铁律级”测试驱动开发svg xmlns http www w3 org 2000 svg style display none svg

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。



 
  
    
     
      
     

在这里插入图片描述

Superpowers - 01 让 AI 真正“懂工程”:Superpowers 软件开发工作流深度解析

Superpowers - 02 用 15 个技能给你的 AI 装上「工程大脑」:Superpowers 快速开始深度解析

Superpowers - 03 一文搞懂 Superpowers:面向多平台 AI 编码助手的安装与实践指南

Superpowers - 04 从“会写代码”到“会做工程”:Superpowers 工作流引擎架构深度剖析

Superpowers - 05 构建一个“会自己找插件用”的 Agent:深入解析 Superpowers 的技能发现与激活机制

Superpowers - 06 从文档到“结构契约”:Superpowers 技能剖析与 Frontmatter 深度解读

Superpowers - 07 从 SessionStart Hook 看 Superpowers:把「技能库」变成「行为操作系统」

Superpowers - 08 在 AI 时代重写「需求评审会」:深入解读 Superpowers 的头脑风暴与设计规范机制

Superpowers - 09 从构思到落地:如何用「计划编写与任务粒度」驾驭 AI 时代的软件开发

Superpowers - 10 用 Subagent 驱动开发,把「AI 写代码」变成一条严谨的生产流水线

Superpowers - 11 从计划到落地:深入解析 Superpowers 的「内联执行计划」工作流


读者对象:有一定工程经验的开发者、对工程实践和 AI 辅助开发感兴趣的研究者与技术爱好者,希望把 TDD 从“知道”升级到“做到、做稳”的人。



  • 赶进度时:“这次先写代码,测试之后补”
  • 修 bug 时:“我已经手动测过边界情况了”
  • 遇到遗留系统:“这块太难写测试了,只能先改了再说”

Superpowers 这套工作流体系,在它的《测试驱动开发循环》文档中,把 TDD 从“工程建议”升级为零妥协的质量准则

NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST —— 没有先失败的测试,就没有生产代码。


Superpowers 给 TDD 下的第一条规则非常直接:

  • 任何生产代码,都必须有对应测试,而且这个测试在实现之前曾经失败过
  • 如果你先写了实现,再补测试:
    • 必须把那段实现 彻底删除
      • 不能当“参考实现”留在某处;
      • 写测试时不能“偷看”它;
      • 重写实现时也不能把它当模板。

原因也写得很白:这是为了对抗认知偏差——一旦你先写了实现,大脑会自然倾向于写“能证明这段实现没错”的测试,而不是验证“这段行为应该是什么”。

事后补的测试回答的是:“它现在在做什么?”
先写的测试回答的是:“它应该做什么?”

唯一被允许的例外,是一次性原型、生成代码和配置文件,而且必须经过“人类搭档”的明确许可。这也暗示了一个前提:这套工作流默认你在一个“人 + AI”协作环境里工作,AI 不能自说自话给自己开“例外许可”。


为什么要“删到看不见”:任何被保留下来的未验证实现,都会在心理上形成“引力场”。稍不注意,你就会开始改写它,而不是从需求推导出一个更干净的解。

这条规则的实际含义是:

  • 违反 TDD 的成本被显式抬高
    • 不是“多写点测试就算补救”;
    • 而是“你刚才那一小时的工作要全部作废”。
  • 于是你会更谨慎地在一开始就说服自己:“这次就先写实现吧”——因为代价不是“挨一顿 code review”,而是“删掉重来”。

  1. RED:写一个会失败的测试
  2. 验证 RED:运行测试,确认 因正确原因失败
  3. GREEN:写最小实现让测试通过
  4. 验证 GREEN:运行测试,确认 所有测试全绿且输出干净
  5. REFACTOR:在保持全绿的前提下重构
  6. 下一轮测试:回到 RED,继续下一个行为

在 RED 步骤,文档强调几点:

  • 每个测试只覆盖 一个行为(名称中如果有“和”,就是危险信号);
  • 尽量使用 真实组件和真实代码路径,只在不得不隔离副作用或外部依赖时才使用 mock;
  • 测试的名字和结构,要能清晰展示 期望的 API 契约

一个典型例子:重试逻辑的两种写法。

写法 示例思路 测真实行为 传入一个会失败几次再成功的操作,用变量记录执行次数,断言“最多执行 3 次且最终成功” 测 mock 行为 mock 掉操作函数,断言“mock 被调用了 3 次”

Superpowers 明确站队前者:测试的对象是行为,不是 mock 本身。


这一关卡常常被很多人跳过:写了测试就直接去写实现。Superpowers 强制要求,你必须先:

  • 运行测试,并观察结果;
  • 要求结果满足:
    • 是一个“失败”,而不是“报错崩溃”;
    • 失败的消息和数据,符合你预期的缺失行为。

如果:

  • 测试一上来就通过:说明你测试的是已有行为,不是你要引入的新能力——需要重新设计测试;
  • 测试因为意料之外的异常抛错:说明测试本身有 bug,而不是系统暂时缺少的行为。你需要先修正测试,再继续循环。

这一步的价值在于:确认测试本身是“有效告警器”,否则后面所有的 “绿” 都失去意义。


实现阶段的指导原则是:用最少的代码让测试通过。 文档特地列了一个重试逻辑的对比:

  • 好的版本:几行循环,固定次数尝试,失败就抛;
  • 坏的版本:一上来就支持退避策略、扩展配置对象、生命周期回调……这些当前测试根本不需要的复杂度。

这里把 YAGNI(You Aren’t Gonna Need It)从理念落到了规则层面:

  • 任何测试不要求的行为和配置,先不要写;
  • 真需要时,让新测试来“逼”出这些能力。

验证 GREEN 阶段除了确认刚写的测试通过,还有两个关键要求:

  • 所有既有测试也必须继续通过:避免引入回归;
  • 测试输出必须干净:不能夹带错误和警告。

重构阶段的范围被限制在三件事:

  • 消除重复;
  • 改善命名;
  • 提取辅助函数。

显式禁止在这一步引入新行为。如果你发现需要新行为,就回到 RED 写新测试。


TDD 不只适用于新功能,同样适用于 bug 修复。

举一个典型例子:“空邮箱也被接受”的 bug

流程被明确写成一个 TDD 循环:

  1. RED:写 test('rejects empty email'),期望返回错误 "Email required"
  2. 验证 RED:测试失败,提示 expected 'Email required', got undefined——正是我们要修的行为;
  3. GREEN:在实现里加入 if (!data.email?.trim()) 这样的 guard 分支;
  4. 验证 GREEN:测试通过;
  5. REFACTOR:如果还有其他字段的类似校验,可以抽取公共验证逻辑。

配套的“系统化调试流程”技能还强调:在任何修复之前,必须先做根因分析;TDD 则负责把修复结果“锁死”在测试里,防止回归。

核心观点是:

没有能复现 bug 并验证修复的测试,就不算真正修复。


Superpowers 把 TDD 嵌入到了整条开发流水线中,几个关键集成点如下。

在 Subagent 驱动开发中,Superpowers 会把某些实现任务交给新的“subagent”(可以理解为子 AI Agent)。每个 subagent 在接收到任务时,都会一并收到 TDD 要求。

审查流程分两层:

  1. 规范合规:看它是否按设计规范实现;
  2. 代码质量审查:其中之一就是检查是否按红-绿-重构循环执行、是否存在非 TDD 的“裸实现”。

这意味着:即使是 AI 写的代码,也不能跳过“先写失败测试”的环节,否则会在审查阶段被驳回。


在“内联执行计划”技能中,每个任务的执行都需要伴随验证动作,TDD 循环提供了验证的工具。

  1. 写回归测试;
  2. 在当前状态下运行,测试应当通过(因为当前版本没有 bug);
  3. 撤销修复;
  4. 再运行,测试必须失败;
  5. 恢复修复,再运行,确认通过。

这套流程在实践中非常少见,但从逻辑上极其严谨:它证明你的测试既能抓住 bug,也不会在没有 bug 时“误报”。


TDD 的原则也被灌注到系统化调试流程和代码审查工作流中:

  • 调试流程要求:每一个修复应当有“失败测试 → 修复 → 通过”的证据链;
  • Code Review 指引:不仅看实现是不是“优雅”,还会检查
    • 是否有对应测试;
    • 测试是否在实现之前存在并失败过;
    • 是否覆写了真实行为而非 mock 行为。

TDD 在这里已经不再是“团队文化共识”,而是一套可检查、可拒绝提交的规则。


“好测试” 三个特征:最小化、清晰、彰显意图。

质量维度 好的示例 坏的示例 最小化 每个测试只验证一种行为 test('validates email and domain and whitespace') 同时测多个东西 清晰 test('retries failed operations 3 times') test('test1') 这种没有任何语义的名字 彰显意图 测试明确展示期望的 API 契约 隐藏真实行为,让人看不出“代码应该做什么”

这三个指标的一个共同出发点是:测试本身是一种文档
好的测试应该让你不看实现就能知道“这个系统对外承诺了什么行为”。


配套的 testing-anti-patterns.md 文档列出了五类常见的测试反模式,每一类都配有示例、危害分析、改写版本以及“关卡问题”(用于在写测试前自查)。

反模式 核心问题 关卡函数问题(写之前问自己) 测试 mock 行为 断言的是 mock 是否被调用,而非真实行为 “我是在测试真实组件行为,还是只在测试 mock 的存在?” 生产代码中的测试专属方法 为了测试在生产类里加只给测试用的方法 “这个方法是否只被测试使用?” → 是就挪到测试工具类 盲目 mock 随手把依赖都 mock 掉,忽略真实副作用 “真实方法有哪些副作用?这些副作用能否被更好地测试?” 不完整的 mock 只 mock 部分字段,导致与真实返回结构不一致 “真实 API 响应包含哪些字段?我是不是在制造一个假世界?” 事后补测试 把测试当成实现完成后的装饰步骤 用 TDD 循环替代:“测试→实现→重构→声明完成”

这份文档的核心原则是:


一个有趣的观察:只要你真的严格执行“先写失败测试、再写实现”,你很难落入这些反模式。

原因在于:

  • 在 RED 阶段,你还没有实现,也没有 mock 细节,自然更倾向于以“行为”来描述测试;
  • 如果一开始就走向“测试 mock 行为”,往往意味着你的出发点已经是“如何验证这段实现”,而不是“需求是什么”。

简单说:守住 TDD 顺序,本身就是对测试质量的强约束。


几类开发者常见的“反 TDD 借口”,并给出对应的“现实版本”。

合理化说法 现实情况 “事后补测试效果一样” 补测试只能回答“现在做了什么”,无法约束“应该做什么” “我已经手动测了所有边界情况” 手动测试既不可重复,也不会留痕;“我试的时候能过”不代表覆盖充分 “删掉 X 小时工作太浪费了” 这是典型沉没成本谬误;留下未经验证代码才是真正的技术债务 “TDD 太教条了,务实一点更重要” 所谓“务实”的捷径,大多变成“在线上环境调试”——既慢又危险 “我要先随便写写探索一下” 探索没问题,但探索代码用完就丢;真正要保留的实现必须从 TDD 开始
  • 实现后写测试:思路被现有实现结构绑定,很难跳出既有分支去想“还有什么边界没覆盖”;
  • 实现前写测试:你被迫围绕需求和边界来设计行为,从而自然更容易想到“如果为空?如果超长?如果重复?”这类情况。

几类表明 TDD 纪律已经被破坏的危险信号:

  • 先写了实现才想到测试;
  • 测试一写就通过,从未经历过“红”;
  • 给自己找形形**的“这一次不 TDD 的理由”;
  • 以“参考实现”的名义保存未经测试的代码。

统一的处理方案只有一个:删掉相关实现,从写测试开始重来。

同时,文档也给了一份“测试难度 = 设计问题”的故障排除表,用来应对下面这些常见阻力:

遇到的问题 建议的应对方案 不知道如何写测试 先写出期望的 API 与断言,必要时和人类搭档一起讨论 测试写起来太复杂 设计太复杂;考虑收敛接口或拆分职责 感觉处处要 mock 耦合度太高;尝试依赖注入,降低组件之间的硬耦合 测试 setup 特别庞大 抽取公共辅助函数;仍然庞大则往上看:设计是否过于臃肿?

在把任何工作标记为完成之前,Superpowers 要求至少满足以下八条检查项:

  1. 每个新函数或方法都有测试;
  2. 每个测试在实现之前都被观察到失败;
  3. 每个测试是因为预期的行为缺失而失败,而不是因为打字错误之类的意外;
  4. 为让每个测试通过,你都只写了最小实现;
  5. 所有测试当前都处于通过状态;
  6. 测试输出干净,没有错误和警告;
  7. 测试用的是尽可能真实的代码,仅在必须时使用 mock;
  8. 重要的边界情况和错误路径都被覆盖。

最后把所有内容再次压缩为一句话:


结合上面的内容,可以给出一套相对可落地的引入路径:

  1. 从“验证 RED / 验证 GREEN”开始
    哪怕暂时做不到所有代码都先写测试,也可以先在现有流程中加两条习惯:
    • 每次写完测试先确认它会因为缺少行为而失败;
    • 每次改完实现跑一遍所有测试,确保全绿、无 warning。


  2. 把“删掉非 TDD 实现”变成约定俗成
    • 在团队规范里写明:如果发现自己“先写了实现”,就自觉删掉那段实现,再从测试开始;
    • code review 时可以温和但坚定地提醒这条规则。
  3. 对 bug 修复强制使用 TDD
    • 所有 bug 修复都必须包含一个能复现 bug 的测试;
    • 没有测试的修复不允许合并(可以先在人少的模块上试行)。
  4. 逐步引入反模式检查
    • 在 review 中有意识地检查:这个测试是不是在测 mock 行为?有没有“测试专属的生产方法”?
    • 对特别依赖 mock 的测试,尝试改写为更整合的行为测试。
  5. 在 AI 协作场景里明确要求“子 agent 也要 TDD”
    • 如果你在使用类似 Superpowers 的工具或其他 AI 编程助手,可以在提示词中明确:

 
                        
    
                          
  • “先写失败测试,再写实现”;
  • “所有新代码都需要有测试,并展示测试从失败到通过的过程”。

  • TDD 铁律规定了证据必须以“先失败再通过的测试”这种形式出现;
  • 六步循环保证了你随时都能指出“这段行为是在哪一轮迭代中被引入的”;
  • 反模式与验证清单,则帮助你把 TDD 从“口头信念”变成“可检查的工程纪律”。

而在这条路上,“没有失败测试,就没有生产代码”,也许是最简单粗暴、但也最有效的一条起跑线。

在这里插入图片描述

小讯
上一篇 2026-04-14 15:52
下一篇 2026-04-14 15:50

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/260795.html