mcpField
T
tdd

tdd

github.com/parcadei测试与质量3.9k472 次安装40 周前更新
代码仓库

关于 tdd

tdd 是强制先测试再开发的技能,要求测试先失败,再编写最少实现使其通过。它还规定了规划、编写测试、实现和验证的 Agent 顺序。

主要功能

  1. 01生产代码前先编写失败测试
  2. 02Red-Green-Refactor 工作流
  3. 03依据测试编写最少实现
  4. 04用于规划和验证的 Agent 顺序
  5. 05测试与套件验证清单

适用场景

  1. 01以测试优先方式实现功能
  2. 02为 Bug 修复添加回归测试
  3. 03按 TDD 阶段协调 Agent
  4. 04完成前验证新旧测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/parcadei/continuous-claude-v3 --skill tdd

安装后在 Claude Code 中输入/tdd确认已加载。

详细介绍

/tdd - 测试驱动开发工作流

严格遵循 TDD 工作流:先写测试,再实现。

适用场景

  • “使用 TDD 实现 X”
  • “先写测试,再构建此功能”
  • “先为 X 编写测试,再实现”
  • 任何测试覆盖至关重要的功能
  • 需要回归测试的 Bug 修复

TDD 理念

概述

先写测试。观察测试失败。编写最少的代码使其通过。

核心原则: 如果你没有观察到测试失败,就不知道它是否测试了正确的内容。

违反规则的字面要求,就是违背规则的本意。

铁律

NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST

先写了代码再写测试?删除它,重新开始。

没有例外:

  • 不要把它留作“参考”
  • 写测试时不要“调整”它
  • 不要查看它
  • 删除就是删除

根据测试重新实现。就是这样。

Red-Green-Refactor

RED - 编写失败的测试

编写一个最简测试,说明应该发生什么。

正确示例:

test('retries failed operations 3 times', async () => {
  let attempts = 0;
  const operation = () => {
    attempts++;
    if (attempts < 3) throw new Error('fail');
    return 'success';
  };

  const result = await retryOperation(operation);

  expect(result).toBe('success');
  expect(attempts).toBe(3);
});

名称清晰、测试真实行为、只测试一件事。

错误示例:

test('retry works', async () => {
  const mock = jest.fn()
    .mockRejectedValueOnce(new Error())
    .mockResolvedValueOnce('success');
  await retryOperation(mock);
  expect(mock).toHaveBeenCalledTimes(3);
});

名称含糊、测试的是模拟对象而非代码。

要求:

  • 一个行为
  • 名称清晰
  • 真实代码(除非无法避免,否则不使用 Mock)
验证 RED - 观察它失败

必须执行。绝不跳过。

npm test path/to/test.test.ts
# or
pytest path/to/test_file.py

确认:

  • 测试失败(而非报错)
  • 失败消息符合预期
  • 失败原因是功能缺失(而非拼写错误)

测试通过了? 你测试的是已有行为。修正测试。
测试报错了? 修复错误,重新运行,直到它正确地失败。

GREEN - 编写最少的代码

编写能通过测试的最简单代码。

正确示例:

async function retryOperation<T>(fn: () => Promise<T>): Promise<T> {
  for (let i = 0; i < 3; i++) {
    try {
      return await fn();
    } catch (e) {
      if (i === 2) throw e;
    }
  }
  throw new Error('unreachable');
}

刚好足以通过测试。

错误示例:

async function retryOperation<T>(
  fn: () => Promise<T>,
  options?: {
    maxRetries?: number;
    backoff?: 'linear' | 'exponential';
    onRetry?: (attempt: number) => void;
  }
): Promise<T> {
  // YAGNI - over-engineered
}

不要添加功能、重构其他代码,也不要超出测试要求进行“改进”。

验证 GREEN - 观察它通过

必须执行。

npm test path/to/test.test.ts

确认:

  • 测试通过
  • 其他测试仍然通过
  • 输出干净(没有错误或警告)

测试失败了? 修复代码,不要改测试。
其他测试失败了? 立即修复。

REFACTOR - 清理代码

只有通过测试后才能进行:

  • 消除重复
  • 改进命名
  • 提取辅助函数

确保测试持续通过。不要添加行为。

常见借口

借口事实
“太简单,不值得测试”简单代码也会出错。测试只需 30 秒。
“之后再测试”测试一开始就通过,说明不了任何问题。
“之后测试也能达到同样目的”先写测试 =“这应该做什么?”之后写测试 =“这做了什么?”
“我已经手动测试过了”临时测试 ≠ 系统测试。没有记录,也无法重跑。
“删除数小时的工作太浪费了”沉没成本谬误。保留未经验证的代码就是技术债务。
“留作参考,先写测试”你会据此调整代码。这就是之后写测试。删除就是删除。
“需要先探索一番”可以。丢弃探索结果,从 TDD 开始。
“测试很难 = 设计不清晰”听听测试的反馈。难以测试 = 难以使用。
“TDD 会拖慢我”TDD 比调试更快。务实的做法 = 先写测试。
“手动测试更快”手动测试无法证明边界情况也能正常工作。每次变更后你都得重新测试。

危险信号 - 停下并重新开始

  • 先写代码再写测试
  • 实现后才写测试
  • 测试一开始就通过
  • 无法解释测试为何失败
  • 测试被“留到以后”再添加
  • 找借口说“这次就破例”
  • “我已经手动测试过了”
  • “之后测试也能达到同样目的”
  • “留作参考”或“调整现有代码”

上述任何情况都意味着:删除代码。从 TDD 重新开始。

验证清单

标记工作完成前:

  • 每个新增函数/方法都有测试
  • 实现前观察了每个测试失败
  • 每个测试都因预期原因失败(功能缺失,而非拼写错误)
  • 编写了通过每个测试所需的最少代码
  • 所有测试均通过
  • 输出干净(没有错误或警告)
  • 测试使用真实代码(只有无法避免时才使用 Mock)
  • 覆盖边界情况和错误

无法勾选所有项目?说明你跳过了 TDD。重新开始。

遇到困难时

问题解决方案
不知道如何测试编写期望的 API。先写断言。向你的协作伙伴请教。
测试过于复杂设计过于复杂。简化接口。
必须模拟所有内容代码耦合过于紧密。使用依赖注入。
测试设置过于庞大提取辅助函数。如果仍然复杂?简化设计。

工作流执行

工作流概览

┌────────────┐    ┌──────────┐    ┌──────────┐    ┌───────────┐
│   plan-    │───▶│ arbiter  │───▶│  kraken  │───▶│ arbiter  │
│   agent    │    │          │    │          │    │           │
└────────────┘    └──────────┘    └──────────┘    └───────────┘
   Design          Write           Implement        Verify
   approach        failing         minimal          all tests
                   tests           code             pass

Agent 序列

#Agent角色输出
1plan-agent设计测试用例和实现方案测试计划
2arbiter编写失败的测试(RED 阶段)测试文件
3kraken实现通过测试所需的最少代码(GREEN 阶段)实现
4arbiter运行所有测试,确认没有破坏任何内容测试报告

核心原则

NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST

每个 Agent 都遵循 TDD 合约:

  • arbiter 编写的测试起初必须失败
  • kraken 编写最少的代码来让测试通过
  • arbiter 确认整个测试套件通过

执行

阶段 1:规划测试用例
Task(
  subagent_type="plan-agent",
  prompt="""
  Design TDD approach for: [FEATURE_NAME]

  Define:
  1. What behaviors need to be tested
  2. Edge cases to cover
  3. Expected test structure

  DO NOT write any implementation code.
  Output: Test plan document
  """
)
阶段 2:编写失败的测试(RED)
Task(
  subagent_type="arbiter",
  prompt="""
  Write failing tests for: [FEATURE_NAME]

  Test plan: [from phase 1]

  Requirements:
  - Write tests FIRST
  - Run tests to confirm they FAIL
  - Tests must fail because feature is missing (not syntax errors)
  - Create clear test names describing expected behavior

  DO NOT write any implementation code.
  """
)
阶段 3:实现(GREEN)
Task(
  subagent_type="kraken",
  prompt="""
  Implement MINIMAL code to pass tests: [FEATURE_NAME]

  Tests location: [test file path]

  Requirements:
  - Write ONLY enough code to make tests pass
  - No additional features beyond what tests require
  - No "improvements" or "enhancements"
  - Run tests after each change

  Follow Red-Green-Refactor strictly.
  """
)
阶段 4:验证
Task(
  subagent_type="arbiter",
  prompt="""
  Validate TDD implementation: [FEATURE_NAME]

  - Run full test suite
  - Verify all new tests pass
  - Verify no existing tests broke
  - Check test coverage if available
  """
)

强制执行的 TDD 规则

  1. arbiter 不能编写实现代码
  2. kraken 不能添加未经测试的功能
  3. 实现前测试必须失败
  4. 实现后测试必须通过

示例

User: /tdd Add email validation to the signup form

Claude: Starting /tdd workflow for email validation...

Phase 1: Planning test cases...
[Spawns plan-agent]
Test plan:
- Valid email formats
- Invalid email formats
- Empty email rejection
- Edge cases (unicode, long emails)

Phase 2: Writing failing tests (RED)...
[Spawns arbiter]
✅ 8 tests written, all failing as expected

Phase 3: Implementing minimal code (GREEN)...
[Spawns kraken]
✅ All 8 tests now passing

Phase 4: Validating...
[Spawns arbiter]
✅ 247 tests passing (8 new), 0 failing

TDD workflow complete!

重构阶段(可选)

GREEN 阶段之后,你可以添加一个重构阶段:

Task(
  subagent_type="kraken",
  prompt="""
  Refactor: [FEATURE_NAME]

  - Clean up code while keeping tests green
  - Remove duplication
  - Improve naming
  - Extract helpers if needed

  DO NOT add new behavior. Keep all tests passing.
  """
)

评论

支持 Markdown