- Add language switch link to root README - Translate README.md to docs/zh-CN/README.md - Translate USER-GUIDE.md to docs/zh-CN/USER-GUIDE.md - Translate all 13 reference documents to docs/zh-CN/references/ Key terminology mappings: - context engineering → 上下文工程 - spec-driven development → 规格驱动开发 - context rot → 上下文衰减 - phase → 阶段 - milestone → 里程碑 - roadmap → 路线图 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.4 KiB
原则: 如果在编写 fn 之前能用 expect(fn(input)).toBe(output) 描述行为,TDD 会改善结果。
关键洞察: TDD 工作本质上比标准任务更重 —— 它需要 2-3 个执行周期(RED → GREEN → REFACTOR),每个周期都涉及文件读取、测试运行和可能的调试。TDD 功能获得专门的计划,以确保整个周期内有完整的上下文可用。
<when_to_use_tdd>
何时 TDD 提高质量
TDD 候选(创建 TDD 计划):
- 有明确输入/输出的业务逻辑
- 有请求/响应契约的 API 端点
- 数据转换、解析、格式化
- 验证规则和约束
- 有可测试行为的算法
- 状态机和工作流
- 有清晰规格的工具函数
跳过 TDD(使用带 type="auto" 任务的标准计划):
- UI 布局、样式、视觉组件
- 配置更改
- 连接现有组件的胶水代码
- 一次性脚本和迁移
- 无业务逻辑的简单 CRUD
- 探索性原型
启发式: 能在编写 fn 之前写 expect(fn(input)).toBe(output) 吗?
→ 能:创建 TDD 计划
→ 不能:使用标准计划,事后添加测试(如需要)
</when_to_use_tdd>
<tdd_plan_structure>
TDD 计划结构
每个 TDD 计划通过完整的 RED-GREEN-REFACTOR 循环实现一个功能。
---
phase: XX-name
plan: NN
type: tdd
---
<objective>
[什么功能以及为什么]
Purpose: [该功能 TDD 的设计收益]
Output: [可工作的、已测试的功能]
</objective>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@relevant/source/files.ts
</context>
<feature>
<name>[功能名称]</name>
<files>[源文件, 测试文件]</files>
<behavior>
[可测试术语描述的预期行为]
Cases: 输入 → 预期输出
</behavior>
<implementation>[测试通过后如何实现]</implementation>
</feature>
<verification>
[证明功能有效的测试命令]
</verification>
<success_criteria>
- 失败测试已编写并提交
- 实现通过测试
- 重构完成(如需要)
- 所有 2-3 个提交都存在
</success_criteria>
<output>
完成后,创建包含以下内容的 SUMMARY.md:
- RED: 编写了什么测试,为什么失败
- GREEN: 什么实现让它通过
- REFACTOR: 做了什么清理(如有)
- Commits: 生成的提交列表
</output>
每个 TDD 计划一个功能。 如果功能足够简单可以批量处理,那就足够简单可以跳过 TDD —— 使用标准计划,事后添加测试。 </tdd_plan_structure>
<execution_flow>
红-绿-重构循环
RED - 编写失败测试:
- 按项目约定创建测试文件
- 编写描述预期行为的测试(来自
<behavior>元素) - 运行测试 - 必须失败
- 如果测试通过:功能已存在或测试有误。调查。
- 提交:
test({phase}-{plan}): add failing test for [feature]
GREEN - 实现使其通过:
- 编写使测试通过的最小代码
- 不耍小聪明,不优化 - 只让它工作
- 运行测试 - 必须通过
- 提交:
feat({phase}-{plan}): implement [feature]
REFACTOR(如需要):
- 如果存在明显的改进,清理实现
- 运行测试 - 必须仍然通过
- 仅在做出更改时提交:
refactor({phase}-{plan}): clean up [feature]
结果: 每个 TDD 计划产生 2-3 个原子提交。 </execution_flow>
<test_quality>
好测试 vs 坏测试
测试行为,而非实现:
- 好:"返回格式化的日期字符串"
- 坏:"用正确参数调用 formatDate 辅助函数"
- 测试应该能经受重构
每个测试一个概念:
- 好:分别为有效输入、空输入、畸形输入编写测试
- 坏:用多个断言检查所有边缘情况的单个测试
描述性名称:
- 好:"should reject empty email"、"returns null for invalid ID"
- 坏:"test1"、"handles error"、"works correctly"
不包含实现细节:
- 好:测试公共 API、可观察行为
- 坏:Mock 内部实现、测试私有方法、断言内部状态 </test_quality>
<framework_setup>
测试框架设置(如不存在)
当执行 TDD 计划但没有配置测试框架时,作为 RED 阶段的一部分进行设置:
1. 检测项目类型:
# JavaScript/TypeScript
if [ -f package.json ]; then echo "node"; fi
# Python
if [ -f requirements.txt ] || [ -f pyproject.toml ]; then echo "python"; fi
# Go
if [ -f go.mod ]; then echo "go"; fi
# Rust
if [ -f Cargo.toml ]; then echo "rust"; fi
2. 安装最小框架:
| 项目 | 框架 | 安装 |
|---|---|---|
| Node.js | Jest | npm install -D jest @types/jest ts-jest |
| Node.js (Vite) | Vitest | npm install -D vitest |
| Python | pytest | pip install pytest |
| Go | testing | 内置 |
| Rust | cargo test | 内置 |
3. 按需创建配置:
- Jest: 带 ts-jest preset 的
jest.config.js - Vitest: 带测试全局变量的
vitest.config.ts - pytest:
pytest.ini或pyproject.toml部分
4. 验证设置:
# 运行空测试套件 - 应该以 0 个测试通过
npm test # Node
pytest # Python
go test ./... # Go
cargo test # Rust
5. 创建第一个测试文件: 遵循项目约定的测试位置:
- 源文件旁边的
*.test.ts/*.spec.ts __tests__/目录- 根目录的
tests/目录
框架设置是第一个 TDD 计划 RED 阶段的一次性成本。 </framework_setup>
<error_handling>
错误处理
测试在 RED 阶段没有失败:
- 功能可能已存在 - 调查
- 测试可能有误(没测试你以为的东西)
- 前进前修复
测试在 GREEN 阶段没有通过:
- 调试实现
- 不要跳到重构
- 持续迭代直到绿色
测试在 REFACTOR 阶段失败:
- 撤销重构
- 提交过早
- 用更小的步骤重构
不相关的测试失败:
- 停下来调查
- 可能表明耦合问题
- 前进前修复 </error_handling>
<commit_pattern>
TDD 计划的提交模式
TDD 计划产生 2-3 个原子提交(每个阶段一个):
test(08-02): add failing test for email validation
- Tests valid email formats accepted
- Tests invalid formats rejected
- Tests empty input handling
feat(08-02): implement email validation
- Regex pattern matches RFC 5322
- Returns boolean for validity
- Handles edge cases (empty, null)
refactor(08-02): extract regex to constant (optional)
- Moved pattern to EMAIL_REGEX constant
- No behavior changes
- Tests still pass
与标准计划对比:
- 标准计划:每个任务 1 个提交,每个计划 2-4 个提交
- TDD 计划:单个功能 2-3 个提交
两者遵循相同格式:{type}({phase}-{plan}): {description}
好处:
- 每个提交独立可回滚
- Git bisect 在提交级别工作
- 显示 TDD 纪律的清晰历史
- 与整体提交策略一致 </commit_pattern>
<context_budget>
上下文预算
TDD 计划目标 ~40% 上下文使用率(低于标准计划的 ~50%)。
为什么更低:
- RED 阶段:编写测试、运行测试、可能调试为什么没有失败
- GREEN 阶段:实现、运行测试、可能对失败进行迭代
- REFACTOR 阶段:修改代码、运行测试、验证无回归
每个阶段涉及读取文件、运行命令、分析输出。来回往复本质上比线性任务执行更重。
单一功能聚焦确保整个周期保持完整质量。 </context_budget>