| name | tdd-fix |
| description | TDD 驱动的 Bug 修复流程。当用户描述 Bug、报错、异常、要求修复问题时必须使用此 Skill。 触发关键词包括但不限于:fix、bug、报错、异常、失败、不生效、NullPointerException、NPE、 ClassCastException、空指针、抛异常、500 错误、返回值不对、数据不一致、逻辑错误、 修复、排查、定位问题。即使用户只是说"这个接口有问题"或"这里不对",也应触发此 Skill。 此 Skill 强制 AI 遵循 Red-Green-Verify 三阶段流程,禁止跳过任何阶段。
|
TDD Fix —— TDD 驱动的 Bug 修复流程
适用场景
用户报告了 Bug、异常、错误行为,需要 AI 协助定位并修复。此 Skill 确保修复过程遵循 TDD 纪律:先用失败测试证明 Bug 存在,再做最小修复,最后回归验证。
核心原则:没有亲眼看到测试失败,就无法证明测试真正覆盖了 Bug。
违反规则的字面含义就是违反规则的精神。
执行前:项目适配
在开始三阶段流程之前,AI 必须先了解项目上下文。
1. 读取项目上下文文件
按以下优先级依次查找项目根目录的上下文文件,找到第一个即停止:
| 优先级 | 文件路径 | 说明 |
|---|
| 1 | PROJECT-CONTEXT.md | 公司推荐标准,通用格式 |
| 2 | CLAUDE.md | Claude Code 生态 |
| 3 | .cursorrules | Cursor 生态 |
| 4 | .github/copilot-instructions.md | GitHub Copilot 生态 |
从上下文文件中获取:
- 技术栈版本(Java 版本、Spring Boot 版本、数据库等)
- 测试框架偏好(JUnit5、TestNG、Mockito 版本等)
- 核心模块划分
- 配置驱动逻辑的关键点(如动态开关、多租户配置等)
- 容易被连带影响的模块(如公共工具类、拦截器、AOP 切面等)
- 业务级回归检查项(如有定义)
2. 上下文文件不存在时的降级方案
如果以上文件均不存在,扫描项目根目录的 pom.xml 或 build.gradle,推断:
- Java 版本
- Spring Boot 版本
- 测试相关依赖(JUnit、Mockito、Spring Test 等)
- 数据库驱动(MyBatis/MyBatis-Plus/JPA/Hibernate)
- 其他关键依赖
3. 确认测试运行方式
确认项目使用 mvn test、gradle test 还是其他命令运行测试,以便后续阶段执行。
阶段一:Red(编写失败测试,证明 Bug 存在)
目标
用一个在当前代码下必定失败的测试用例,精确复现 Bug。
步骤
-
分析根因:
- 根据用户描述的现象,定位到具体的类和方法
- 阅读相关源码,理解当前逻辑
- 明确 Bug 的触发条件和错误行为
- 输出根因分析摘要:
[类名]#[方法名] 在 [条件] 下会 [错误行为]
-
编写复现测试:
- 测试命名格式:
should_[期望行为]_when_[触发条件]
- 测试结构遵循 Given/When/Then 三段式
- 参考
templates/unit-test-template.java 中的骨架
- 根据 Bug 性质选择测试类型:
- 纯逻辑问题 → 单元测试(Mockito)
- 涉及 Spring 容器、配置注入 → 集成测试(@SpringBootTest)
- 断言应精确反映"修复后的正确行为",使得当前有 Bug 的代码必定让断言失败
-
执行测试,确认红灯:
- 运行该测试,确认失败
- 记录失败信息(异常类型、断言失败的 expected vs actual)
- 如果测试意外通过,说明 Bug 复现条件不准确,需重新分析
无法编写复现测试的情况
如果 Bug 涉及外部系统调用、文件系统、网络请求等不可控因素,无法直接编写复现测试:
- 必须说明原因:解释为什么无法直接复现
- 给出 Mock 方案:使用 Mockito mock 外部依赖,模拟触发 Bug 的条件
- 如果连 Mock 也不可行:记录到修复报告中,标注为"无自动化复现测试",并说明手动验证方案
构建环境不可用时的降级方案
当项目构建环境不可用(如私有仓库不可达、parent POM 缺失、依赖下载失败等),导致无法通过 mvn test 或 gradle test 实际运行测试时,允许降级为代码走查验证,但必须满足以下三个硬性要求:
- 明确标注降级状态:在 Red 和 Green 阶段的输出中,必须明确标注"本阶段采用代码走查降级验证,测试未实际运行",不得含糊其辞或省略不提
- 修复报告风险评估补充:修复报告的"风险评估"章节中,必须新增一行:
测试执行状态 —— "测试未实际运行,需在 CI/CD 环境或 IDE 中补充验证后方可合并代码"
- 自检清单降级标注:完成前自检清单中,第 2 项(是否亲眼看到了测试失败)和第 4 项(所有测试是否全部通过)不得标记为完全通过,应标注为"部分满足(代码走查降级)"
阶段二:Green(最小化修复,测试变绿)
目标
用最小的代码改动修复 Bug,使阶段一的测试通过。
约束规则
- 只修 Bug,不改无关代码:禁止顺手重构、优化命名、调整格式、添加注释等与 Bug 无关的改动
- 逐文件说明改动理由:如果修复涉及多个文件,必须逐个说明每个文件为什么需要改动
- 保持改动可审查:每个改动应该能用一句话解释清楚
步骤
-
实施修复:
- 根据阶段一的根因分析,编写修复代码
- 只改必要的代码,追求最小改动集
-
运行复现测试,确认绿灯:
- 重新运行阶段一编写的测试
- 确认测试通过
- 如果测试仍然失败,检查修复是否正确,重新修复
-
输出改动清单:
- 列出所有改动的文件
- 每个文件说明:改了什么、为什么要改
阶段三:Verify(回归验证 + 修复报告)
目标
确保修复没有引入新问题,并输出完整的修复报告。
步骤
-
执行回归检查清单:
- 按照
templates/regression-checklist.md 逐项列出每一条检查项的检查结果
- 不得跳过、合并或笼统带过任何检查项,即使该项与本次修复无关也要明确标注"不涉及"
- 如果项目上下文文件中定义了业务级检查项,追加执行
-
运行相关模块测试:
- 运行被修改类所在模块的全部测试
- 如果改动涉及公共组件,扩大测试范围到依赖该组件的模块
- 记录测试结果:总数、通过数、失败数
-
完成前自检:
- 在输出修复报告之前,必须逐项确认以下清单
- 任何一项不满足,必须回到对应阶段重新执行,不得直接输出报告
| # | 自检项 | 对应阶段 |
|---|
| 1 | 每个修复点是否都有对应的测试 | Red |
| 2 | 是否亲眼看到了测试失败(红灯) | Red |
| 3 | 是否只写了最小化代码让测试通过 | Green |
| 4 | 所有测试是否全部通过 | Green |
| 5 | 测试是否使用了真实代码而非过度 Mock | Red |
| 6 | 边界情况和异常路径是否覆盖 | Red |
无法全部打勾?说明跳过了 TDD 步骤,必须回退重做。
-
输出修复报告:
- 严格按照
templates/fix-report-template.md 的章节结构输出,不得省略任何章节,不得自行更改格式
- 模板中的每个字段都必须填写,包括:严重程度、影响范围、多环境兼容性等
- 如果某个字段确实不适用,填写"不适用"并简要说明原因,而不是删除该字段
流程约束(不可跳过)
| 规则 | 说明 |
|---|
| 禁止跳过 Red 阶段 | 没有失败测试就不能开始修复 |
| 禁止跳过 Green 确认 | 修复后必须运行测试确认通过 |
| 禁止跳过回归验证 | 必须检查是否引入新问题 |
| 禁止顺手重构 | 只修 Bug,不做任何无关改动 |
| 测试命名规范 | should_xxx_when_xxx 格式 |
| 改动需说明理由 | 多文件改动时逐个说明 |
常见借口与应对
以下是 AI 试图跳过 TDD 流程时最常见的借口。出现这些想法时必须立即停止并纠正。
| 借口 | 现实 |
|---|
| "这个改动太简单了不需要测试" | 简单的改动测试也只需要 30 秒,没有理由跳过。简单代码也会出 Bug。 |
| "先改完再补测试" | 测试后补无法证明测试能捕获 Bug——测试直接通过说明不了任何问题。必须先看到红灯。 |
| "手动测试过了没问题" | 手动测试无法复现、无法回归、无记录。"我试了没问题" ≠ 全面覆盖。 |
| "写测试太复杂了" | 如果测试难写,说明代码设计有问题。用 Mock 方案隔离依赖,或重新审视接口设计。 |
| "时间紧来不及写测试" | TDD 比修复线上 Bug 快得多。跳过测试是用未来的时间偿还现在的懒惰。 |
| "已有代码没有测试,加不上去" | 你正在改进它。为你修改的部分补上测试。 |
| "先写完留着做参考,再按 TDD 来" | 你会不自觉地"适配"已有代码,那就不是 TDD 了。删掉,从测试开始。 |
| "TDD 太教条了,我更务实" | TDD 本身就是务实的——提前发现 Bug、防止回归、记录行为、支持重构。跳过测试才是在制造技术债。 |
红线信号——出现以下任何一种情况,必须停下来从 Red 阶段重新开始:
- 在测试之前就写了修复代码
- 测试第一次运行就通过了(说明没有真正覆盖 Bug)
- 无法解释测试为什么失败
- 打算"之后再补"测试
- 心里在想"就这一次可以跳过"
完整示例
参考 examples/example-bug-fix.md 查看一个从 Red 到 Green 到 Verify 的完整修复流程示例。
对应的测试代码见 examples/example-test-output.java。