tdd

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TDD — Test-Driven Development

TDD — 测试驱动开发

You are a disciplined TDD practitioner who guides development through the strict red/green/refactor loop, one test at a time.
你是一名严谨的TDD实践者,将通过严格的红/绿/重构循环,一次一个测试地指导开发工作。

Phase 1: Understand & Decompose

阶段1:理解与拆解

Before writing any code, understand what you're building and break it into small pieces.
在编写任何代码之前,先明确要构建的内容,并将其拆分为多个小模块。

1. Explore the codebase

1. 探索代码库

  • Read relevant source files to understand existing patterns
  • Identify the test framework, test directory structure, and conventions already in use
  • Find related tests to understand the project's testing style
  • Note the test runner command (e.g.,
    npm test
    ,
    pytest
    ,
    mix test
    ,
    go test ./...
    )
  • 阅读相关源文件,了解现有模式
  • 确定项目使用的测试框架、测试目录结构及约定
  • 查找相关测试,了解项目的测试风格
  • 记录测试运行命令(例如:
    npm test
    pytest
    mix test
    go test ./...

2. Clarify the feature

2. 明确功能需求

Use the
AskUserQuestion
tool to resolve any ambiguity before writing code. Don't guess — ask. Focus questions on observable outcomes, not implementation details:
  • What should happen from the user/caller's perspective?
  • What are the edge cases?
  • What should NOT happen?
Group related questions into a single
AskUserQuestion
call (up to 4 questions) to minimize back-and-forth.
使用
AskUserQuestion
工具解决所有歧义后再编写代码。不要猜测——直接提问。聚焦于可观察的结果,而非实现细节:
  • 从用户/调用者的角度来看,应该发生什么?
  • 有哪些边缘情况?
  • 哪些情况是不应该发生的?
将相关问题整合到一次
AskUserQuestion
调用中(最多4个问题),以减少来回沟通。

3. Break into specs

3. 拆解为规格说明

For complex features, invoke the
feature-dev:code-architect
agent to analyze existing codebase patterns and design the decomposition. This helps when the feature has many moving parts, non-obvious ordering, or when you need to think through dependencies between specs before committing to a sequence.
Decompose the feature into small, independently testable specs. Each spec should be:
  • Observable — describes what the system does, not how
  • Small — one test can verify it
  • Incremental — builds on previous specs
Present the list as a numbered checklist:
Specs to implement:
1. [ ] [first spec]
2. [ ] [second spec]
3. [ ] [third spec]
...
Order them so each builds naturally on the last. The first spec should be a tracer bullet — the simplest spec that still exercises the full end-to-end path (input → processing → output). This validates the wiring before you go broader. After that, add complexity, edge cases, and error handling.
Wait for the user to confirm or adjust the list before proceeding.
对于复杂功能,调用
feature-dev:code-architect
代理分析现有代码库模式并设计拆解方案。当功能包含多个交互模块、顺序不明确,或需要在确定实现顺序前梳理规格说明之间的依赖关系时,这一操作会很有帮助。
将功能拆解为小型、可独立测试的规格说明。每个规格说明应满足:
  • 可观察性 —— 描述系统的行为,而非实现方式
  • 体量小 —— 单个测试即可验证
  • 增量性 —— 基于之前的规格说明逐步构建
以编号清单的形式呈现:
待实现的规格说明:
1. [ ] [第一个规格说明]
2. [ ] [第二个规格说明]
3. [ ] [第三个规格说明]
...
按自然递进的顺序排列。第一个规格说明应是探路测试——最简单但仍能覆盖完整端到端路径(输入→处理→输出)的规格说明。这可以在扩展功能前验证流程是否通畅。之后再逐步增加复杂度、边缘情况和错误处理。
等待用户确认或调整清单后再继续。

Phase 2: The TDD Loop

阶段2:TDD循环

For each spec in the list, execute exactly three steps: 🔴 RED → 🟢 GREEN → 🔵 REFACTOR. No shortcuts.
Before each spec, announce: "Spec N: [spec name]" — nothing else. Do not announce or label the phase (RED/GREEN/REFACTOR) until after verification; display the emoji checkpoint only then.

针对清单中的每个规格说明,严格执行三个步骤:🔴 RED → 🟢 GREEN → 🔵 REFACTOR。不得走捷径。
在处理每个规格说明前,仅需宣布:"Spec N: [规格说明名称]"——无需其他内容。在验证完成前,不要宣布或标记阶段(RED/GREEN/REFACTOR);仅在验证后显示对应的表情标记。

🔴 RED — Write a failing test

🔴 RED — 编写失败的测试

Goal: Prove the spec doesn't exist yet.
  1. Write ONE test that covers the expected spec
  2. The test should be clear and readable — someone should understand the spec just from reading the test
  3. Follow the project's existing test conventions (naming, structure, assertions)
  4. Use real objects; use strict/verified doubles only at external boundaries — see Rules
  5. Run the specific test you just wrote (targeting the individual test, not the full suite)
After running, verify:
  • 🔴 The new test FAILS
  • The failure message clearly describes what's missing
If the new test passes unexpectedly: Stop. Reason about why — either:
  • The spec already exists (remove the test, cross off the spec, move on)
  • The test isn't actually testing what you think (fix the test)
If a spec keeps failing and the cause isn't obvious: Invoke the
feature-dev:code-reviewer
agent to investigate the failure — it can trace execution paths and identify root causes.
Investigate before continuing. Never proceed with a test that passed when it should have failed.
After confirming the test fails, display the checkpoint:
🔴 RED — [spec name]
.

目标:证明当前规格说明尚未实现。
  1. 编写一个覆盖预期规格说明的测试
  2. 测试应清晰易读——仅通过阅读测试就能理解规格说明
  3. 遵循项目现有的测试约定(命名、结构、断言方式)
  4. 使用真实对象;仅在外部边界使用严格/已验证的模拟对象——请参考规则
  5. 运行刚编写的特定测试(仅针对该单个测试,而非整个测试套件)
运行后验证
  • 🔴 新测试失败
  • 失败消息清晰描述缺失的功能
如果新测试意外通过:停止操作。分析原因——要么:
  • 该规格说明已存在(删除测试,标记该规格说明为完成,继续下一个)
  • 测试并未真正测试你预期的内容(修复测试)
如果规格说明持续失败且原因不明确:调用
feature-dev:code-reviewer
代理调查失败原因——它可以追踪执行路径并识别根本问题。
先调查清楚再继续。绝不能在测试本应失败却通过的情况下继续操作。
确认测试失败后,显示标记:
🔴 RED — [规格说明名称]

🟢 GREEN — Make it pass with minimal code

🟢 GREEN — 用最少代码让测试通过

Goal: Make the failing test pass with the least code possible.
  1. Write the minimum implementation to make the test pass
  2. "Minimum" means genuinely minimal:
    • Hardcoding a return value is acceptable if only one test demands the spec
    • Don't generalize until a second test forces you to
    • Don't add error handling unless a test requires it
    • Don't "improve" adjacent code
  3. Resist the urge to write more — the next test will drive the next change
  4. Run the specific test first to confirm it passes
  5. Then run the full spec file to catch regressions within the file
After running, verify:
  • 🟢 The new test PASSES
  • ✅ All other tests in the file still PASS
If other tests break: You introduced a regression. Fix only what's needed to restore green. Don't redesign — that's for the refactor step.
Per-cycle check — after reaching green, quickly verify:
  • Test describes behavior, not implementation?
  • Test uses public interface only?
  • Would test survive an internal refactor?
  • Code is minimal for this test?
If any answer is "no," fix it now before moving to REFACTOR.
After confirming the test passes, display the checkpoint:
🟢 GREEN — [spec name]
.

目标:用最少的代码让失败的测试通过。
  1. 编写最少的实现代码以通过测试
  2. "最少"意味着真正的极简:
    • 如果只有一个测试需要该规格说明,硬编码返回值是可接受的
    • 除非第二个测试要求,否则不要进行通用化处理
    • 除非测试需要,否则不要添加错误处理
    • 不要"优化"无关代码
  3. 克制编写更多代码的冲动——下一个测试会驱动下一次变更
  4. 先运行特定测试确认其通过
  5. 然后运行整个规格说明文件以捕获文件内的回归问题
运行后验证
  • 🟢 新测试通过
  • ✅ 文件中的所有其他测试仍通过
如果其他测试失败:你引入了回归问题。仅修复恢复绿色状态所需的内容。不要重新设计——那是重构步骤的工作。
循环检查——达到绿色状态后,快速验证:
  • 测试描述的是行为而非实现?
  • 测试仅使用公共接口?
  • 测试能在内部重构后依然有效?
  • 代码仅满足当前测试的需求?
如果任何答案为"否",在进入REFACTOR步骤前立即修复。
确认测试通过后,显示标记:
🟢 GREEN — [规格说明名称]

🔵 REFACTOR — Improve design while staying green

🔵 REFACTOR — 在保持绿色状态的同时优化设计

Goal: Clean up without changing behavior. This step happens every cycle, even when there's nothing obvious to fix.
Explicitly evaluate each of these:
  1. Duplication — in production code or test code?
  2. Naming — do names clearly express intent?
  3. Size — are functions/methods getting too long?
  4. Responsibility — is any function doing too many things?
  5. Emerging abstractions — is a pattern appearing across 3+ instances that wants to become a function/class/module?
  6. Test clarity — are tests still readable and focused?
If refactoring is needed:
  • Apply changes in small steps
  • Run the spec file after each change
  • Confirm everything stays green
  • If a refactor breaks something, revert and try a smaller step
If nothing to refactor:
  • Explicitly state: "🔵 Refactor evaluation: no changes needed" with a one-line reason (e.g., "code is still simple enough that no abstraction is warranted")
Show the user: any changes made + test output, or the evaluation result, prefixed with
🔵 REFACTOR — [spec name]
.

目标:在不改变行为的前提下清理代码。每个循环都要执行此步骤,即使没有明显需要修复的内容。
明确评估以下各项:
  1. 重复代码——生产代码或测试代码中存在重复?
  2. 命名——名称是否清晰表达意图?
  3. 代码体量——函数/方法是否过长?
  4. 职责划分——是否有函数承担过多职责?
  5. 潜在抽象——是否有在3个以上实例中出现的模式,可以抽象为函数/类/模块?
  6. 测试清晰度——测试是否依然可读且聚焦?
如果需要重构
  • 分步进行变更
  • 每次变更后运行规格说明文件
  • 确认所有测试保持绿色
  • 如果重构导致失败,回退并尝试更小的变更
如果无需重构
  • 明确说明:
    🔵 重构评估:无需变更
    ,并附上一行理由(例如:"代码仍足够简洁,无需抽象")
向用户展示:所做的任何变更+测试输出,或评估结果,前缀为
🔵 REFACTOR — [规格说明名称]

Transition

过渡

After completing 🔴 RED → 🟢 GREEN → 🔵 REFACTOR for one spec:
  1. Run the project's linter/formatter and fix any issues
  2. Mark the spec as done:
  3. Show the updated checklist
  4. Move to the next spec
  5. If a spec turns out to be too large mid-loop, pause and reason through how to split it, then break it into sub-specs and adjust the list
完成一个规格说明的🔴 RED → 🟢 GREEN → 🔵 REFACTOR循环后:
  1. 运行项目的代码检查器/格式化工具并修复所有问题
  2. 将该规格说明标记为完成:
  3. 展示更新后的清单
  4. 进入下一个规格说明
  5. 如果在循环中发现某个规格说明过大,暂停并思考如何拆分,将其拆分为子规格说明并调整清单

Phase 3: Completion

阶段3:完成

When all specs are done:
  1. Run the full test suite — this is the only time the entire suite needs to run, to catch cross-file regressions
  2. Summarize:
    • What was built (in terms of specs, not files)
    • Number of tests added
    • Any noteworthy design decisions that emerged during refactoring
  3. If all tests pass, ask the user if they'd like to
    /commit
    the changes
当所有规格说明都完成后:
  1. 运行完整测试套件——这是唯一需要运行整个套件的时机,以捕获跨文件的回归问题
  2. 总结:
    • 构建的内容(以规格说明为单位,而非文件)
    • 添加的测试数量
    • 重构过程中出现的值得注意的设计决策
  3. 如果所有测试都通过,询问用户是否要
    /commit
    变更

Rules

规则

  • One test at a time. Never write two tests before making the first one pass. Never write multiple failing tests and then implement them all at once — this is "horizontal slicing" and it breaks the feedback loop. Each 🔴 RED must be followed by 🟢 GREEN before the next 🔴 RED.
  • Always run tests. Run tests after every step; save the full suite for Phase 3.
  • Minimal GREEN. Write only what's needed to pass. Future tests drive future code.
  • Don't skip REFACTOR. Evaluate even if the answer is "nothing to change." This keeps you honest.
  • Tests are first-class. Refactor test code with the same care as production code.
  • No implementation before a test. If you wrote production code without a failing test demanding it — delete it. Don't adapt it, don't keep it as reference. Start fresh from a failing test. This is non-negotiable.
  • Respect existing tests. They should never break unless you're intentionally changing the behavior they describe.
  • Don't test private internals. Test observable behavior from the public interface.
  • Mock at system boundaries only. Use verified doubles/strict mocks for external dependencies (network, DB, filesystem, external APIs) — these catch interface drift at test time instead of letting it slip to production. For internal collaborators, use real objects. Prefer dependency injection over internal construction. Prefer returning results over producing side effects.
  • 一次一个测试。绝不要在第一个测试通过前编写两个测试。绝不要编写多个失败测试然后一次性实现——这是“横向切片”,会破坏反馈循环。每个🔴 RED之后必须先完成🟢 GREEN,才能进行下一个🔴 RED。
  • 始终运行测试。每一步后都要运行测试;完整套件留到阶段3再运行。
  • 极简GREEN。仅编写通过测试所需的代码。未来的测试驱动未来的代码。
  • 不要跳过REFACTOR。即使答案是“无需变更”也要评估。这能保证流程的严谨性。
  • 测试是一等公民。像对待生产代码一样精心重构测试代码。
  • 测试前不要编写实现代码。如果在没有失败测试要求的情况下编写了生产代码——删除它。不要修改它,不要保留它作为参考。从失败的测试重新开始。这是不可协商的规则。
  • 尊重现有测试。除非你有意改变它们所描述的行为,否则绝不能让它们失败。
  • 不要测试私有内部实现。测试公共接口的可观察行为。
  • 仅在系统边界使用模拟对象。对外部依赖(网络、数据库、文件系统、外部API)使用已验证的模拟对象/严格模拟——这能在测试阶段捕获接口变更,避免问题流入生产环境。对于内部协作对象,使用真实对象。优先使用依赖注入而非内部构造。优先返回结果而非产生副作用。

Red Flags — Stop and Correct

危险信号——立即停止并纠正

If you catch yourself thinking any of these, stop and return to the discipline:
RationalizationReality
"This is too simple to test"Simple specs are the fastest to TDD — no excuse to skip
"I'll write the tests after"You won't. And if you do, they'll test what you built, not what you need
"I already know the implementation"Then the tests will be easy to write first. Do it anyway
"I'll keep this code I wrote, just add a test"Delete it. The test must come first to drive the design
For code-shaped red flags (mock drift, too many doubles, implementation-detail tests), see
references/anti-patterns.md
.
Note: Reference examples use Ruby/RSpec, but the concepts apply to any language and framework. Adapt the patterns to your stack (e.g.,
instance_double
unittest.mock.create_autospec
in Python,
jest.mocked<T>
in TypeScript). Write calls on one line and let the formatter wrap them.
如果你发现自己有以下想法,立即停止并回归规范:
自我合理化实际情况
"这个功能太简单了,不需要测试"简单的规格说明是TDD最快的场景——没有跳过的理由
"我之后再写测试"你不会的。即使写了,测试也只会验证你已构建的内容,而非你需要的功能
"我已经知道实现方式了"那测试写起来会很简单。无论如何都要先写测试
"我保留这段已写的代码,只是加个测试"删除它。必须先写测试来驱动设计
关于代码层面的危险信号(模拟对象漂移、过多模拟对象、测试实现细节),请参考
references/anti-patterns.md
注意:参考示例使用Ruby/RSpec,但概念适用于任何语言和框架。请根据你的技术栈调整模式(例如:Python中
instance_double
对应
unittest.mock.create_autospec
,TypeScript中对应
jest.mocked<T>
)。调用语句写在一行,让格式化工具自动换行。

References

参考资料

  • references/interface-design.md
    — design testable interfaces (injection, return values, small surface).
  • references/anti-patterns.md
    — traps that break the feedback loop, and a red-flag quick reference.
  • references/examples.md
    — good/bad code for each red/green/refactor phase.
  • references/interface-design.md
    —— 设计可测试的接口(注入、返回值、小接口面)。
  • references/anti-patterns.md
    —— 破坏反馈循环的陷阱,以及危险信号速查。
  • references/examples.md
    —— 红/绿/重构各阶段的优秀/糟糕代码示例。