首页 › tutorials › Claude Code测试驱动开发全实战

Claude Code 测试驱动开发全实战:从 Red-Green-Refactor 到自动化质量守门

学习目标:掌握用 Claude Code 实施严格 TDD 工作流的完整方法——包括 CLAUDE.md 测试规则配置、Red-Green-Refactor 循环实操、自定义 TDD Skill 编写、Hooks 自动化测试守门、以及一个完整的全栈项目实战案例。阅读完毕后,你将能在任何项目中让 Claude Code 严格遵循"测试先行"纪律,彻底告别 AI 默认的"实现先行"陷阱。

适用人群:已具备 Claude Code 基础使用经验的前端/后端/全栈开发者,希望将 AI 编码助手纳入 TDD 纪律框架的工程师,以及团队技术负责人。


一、为什么 Claude Code 需要"被约束"的 TDD

1.1 Claude Code 的结构性缺陷:实现先行

Claude Code 是当前最强大的 AI 编码助手之一,但它有一个根深蒂固的行为倾向——默认实现先行(Implementation-First)。当你给它一个需求描述,它的第一反应是直接写功能代码,测试要么被忽略,要么被敷衍。

用户:帮我写一个用户注册功能

Claude Code(默认行为):
  ✅ 立即创建 UserService.java
  ✅ 立即实现 register() 方法
  ✅ 顺手写个 Controller
  ❌ 没有先写测试
  ❌ 边界条件未覆盖
  ❌ 错误路径未验证

这不是 Claude Code 的 bug,而是大语言模型推理模式的固有特征——它倾向于从"最可能的解决方案"开始生成,而测试用例需要从"所有可能失败的场景"出发思考,两者思维方向截然相反。

1.2 TDD 的三层价值在 AI 时代更加凸显

TDD 价值层 传统开发中的作用 AI 辅助开发中的作用
需求澄清 帮助开发者理解需求 作为 AI 的精确需求规约,消除歧义
安全网 防止回归错误 验证 AI 生成代码的正确性,防止"看起来对但实际错"
设计指引 驱动更好的 API 设计 约束 AI 的代码结构,防止过度工程化

1.3 Claude Code + TDD 的正确姿势

要让 Claude Code 真正遵循 TDD,需要三层防线:

graph TB
    subgraph "三层TDD防线"
        A["第一层:CLAUDE.md<br/>测试规则与质量标准"]
        B["第二层:Custom TDD Skill<br/>强制 Red-Green-Refactor 流程"]
        C["第三层:Hooks<br/>自动运行测试守门"]
    end
    A --> B --> C
    C -->|"测试失败则阻断"| D["阻止低质量代码合入"]
    style A fill:#f9f,stroke:#333
    style B fill:#bbf,stroke:#333
    style C fill:#bfb,stroke:#333
    style D fill:#fbb,stroke:#333

二、前置条件与环境准备

2.1 基础要求

2.2 安装与验证

# 安装 Claude Code(如果尚未安装)
npm install -g @anthropic-ai/claude-code

# 验证版本
claude --version
# 期望输出:2.1.x 或更高

# 进入你的项目目录
mkdir tdd-demo && cd tdd-demo
git init

# 初始化 Claude Code 项目配置
claude /init

2.3 测试框架选型建议

语言/框架 推荐测试工具 命令
TypeScript/JavaScript Vitest(推荐)或 Jest npx vitest / npx jest
Python pytest pytest
Go 标准库 testing + testify go test ./...
Java JUnit 5 + Mockito mvn test

本文所有示例使用 Vitest + TypeScript,但原则适用于所有语言。


三、第一层防线:CLAUDE.md 测试规则配置

3.1 为什么 CLAUDE.md 是 TDD 的基石

CLAUDE.md 是 Claude Code 的"项目宪法"。在其中声明测试规则,等于告诉 AI:"在这个项目中,测试不是可选的,而是强制的前置步骤。"

3.2 完整的测试规则配置

在项目根目录创建或编辑 CLAUDE.md,加入以下测试相关段落:

# Testing Standards

## TDD Discipline (MANDATORY)
- ALWAYS write tests BEFORE implementation code
- Follow strict Red-Green-Refactor cycle:
  1. RED: Write a failing test that defines expected behavior
  2. GREEN: Write the MINIMUM code to make the test pass
  3. REFACTOR: Improve code while keeping all tests green
- NEVER skip the RED phase — tests must fail first to prove they test something

## Test Quality Rules
- Test behavior, NOT implementation details
- Use descriptive test names: `should [expected behavior] when [condition]`
- Each test must have exactly ONE assertion focus
- Cover: happy path, edge cases, error paths
- Minimum coverage target: 80% for new code
- NEVER mock what you don't own — wrap external dependencies behind interfaces

## Test Commands
- Run all tests: `npx vitest run`
- Run single file: `npx vitest run path/to/test.ts`
- Watch mode: `npx vitest`
- Coverage: `npx vitest run --coverage`

## File Naming Conventions
- Test files: `*.test.ts` or `*.spec.ts`
- Test directory mirrors source: `src/auth/login.ts` → `src/auth/login.test.ts`
- Test utilities: `test/helpers/` or `test/fixtures/`

## Forbidden Patterns
- ❌ DO NOT write `expect(true).toBe(true)` placeholder tests
- ❌ DO NOT test private methods directly
- ❌ DO NOT use `any` types in test code
- ❌ DO NOT skip failing tests with `.skip()` without a linked issue

3.3 规则生效验证

配置完成后,用以下命令验证 Claude Code 是否遵守规则:

claude "帮我创建一个计算器模块,支持加减乘除"

预期行为: - Claude Code 应该先创建测试文件 calculator.test.ts - 然后运行测试,确认红灯(测试失败) - 最后才写 calculator.ts 实现 - 运行测试,确认绿灯

如果 Claude Code 直接写了实现代码而没有先写测试,说明 CLAUDE.md 规则需要更明确的措辞,或者需要进入下一层——自定义 TDD Skill。


四、第二层防线:自定义 TDD Skill 强制流程

4.1 Skill 如何解决"AI 不守纪律"问题

CLAUDE.md 是"建议",Skill 是"流程"。一个 TDD Skill 把 Red-Green-Refactor 编排为 Claude Code 必须遵循的子代理序列,每一步都有明确的输入输出和验证条件。

4.2 创建 TDD Skill

在项目根目录创建 .claude/skills/tdd.md:

---
name: tdd
description: >
  Enforce strict Test-Driven Development. Use when implementing new features,
  fixing bugs, or refactoring code. Orchestrates the Red-Green-Refactor cycle
  through subagents, ensuring tests are written and verified BEFORE implementation.
---

You are a TDD discipline enforcer. When the user asks you to implement or modify
any functionality, you MUST follow this exact sequence:

## Phase 1: RED (Write Failing Test)

1. Analyze the user's requirement and identify the expected behavior
2. Create a test file following project conventions (*.test.ts)
3. Write test cases that cover:
   - Happy path (normal input → expected output)
   - Edge cases (boundary values, empty input, null/undefined)
   - Error paths (invalid input → expected error)
4. Run the test command: `npx vitest run <test-file>`
5. VERIFY the test FAILS — if it passes, the test is wrong
6. Report: "🔴 RED: <number> tests failing as expected"

## Phase 2: GREEN (Minimum Implementation)

1. Write the MINIMUM code required to make failing tests pass
2. Do NOT add extra features, optimizations, or "nice-to-haves"
3. Run the test command again: `npx vitest run <test-file>`
4. VERIFY ALL tests pass — if any still fail, fix implementation
5. Report: "🟢 GREEN: All tests passing"

## Phase 3: REFACTOR (Improve Code Quality)

1. Review the implementation for:
   - Code duplication
   - Poor naming
   - Violations of SOLID principles
   - Performance bottlenecks
2. Make improvements while keeping tests green
3. Run tests after EACH refactor step
4. Report: "♻️ REFACTOR: <list of improvements made>"

## Rules
- NEVER skip Phase 1 (RED)
- NEVER implement more than what tests require in Phase 2 (GREEN)
- NEVER break tests during Phase 3 (REFACTOR)
- If user asks to skip tests, respond: "TDD is mandatory in this project. I'll proceed with the full Red-Green-Refactor cycle."

4.3 TDD Skill 的执行流程

sequenceDiagram
    participant U as 用户
    participant CC as Claude Code
    participant T as 测试框架(Vitest)
    participant S as 源代码

    U->>CC: /tdd 实现 XXX 功能

    rect rgb(255, 200, 200)
        Note over CC,T: Phase 1: RED
        CC->>T: 编写测试用例
        CC->>T: 运行 npx vitest run
        T-->>CC: ❌ 测试失败(预期)
        CC->>U: 🔴 RED: 3 tests failing
    end

    rect rgb(200, 255, 200)
        Note over CC,S: Phase 2: GREEN
        CC->>S: 编写最小实现
        CC->>T: 运行 npx vitest run
        T-->>CC: ✅ 测试全部通过
        CC->>U: 🟢 GREEN: All tests passing
    end

    rect rgb(200, 220, 255)
        Note over CC,S: Phase 3: REFACTOR
        CC->>S: 重构改进代码
        CC->>T: 每次重构后运行测试
        T-->>CC: ✅ 测试仍然通过
        CC->>U: ♻️ REFACTOR: 提取公共方法+优化命名
    end

4.4 使用 TDD Skill

# 方式一:直接调用
claude "/tdd 实现一个用户认证模块,支持邮箱密码注册和登录"

# 方式二:在对话中触发
claude
> 用TDD方式帮我实现购物车的计算总价功能
# Claude Code 会自动检测到 "实现" 关键词,按照 TDD 流程执行

五、第三层防线:Hooks 自动化测试守门

5.1 什么是 Hooks

Hooks 是 Claude Code 的生命周期钩子——在特定事件发生时自动执行 shell 命令。对于 TDD,我们主要用两类 Hook:

5.2 配置自动化测试 Hook

编辑项目级配置文件 .claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "cd \"$PROJECT_DIR\" && npx vitest run --reporter=verbose 2>&1 | tail -20"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "sh -c 'FILE=\"$CLAUDE_FILE_PATH\"; if echo \"$FILE\" | grep -qv \"\\.test\\.\"; then echo \"⚠️ Source file modified — ensure corresponding tests exist\"; fi'"
          }
        ]
      }
    ]
  }
}

5.3 Hook 工作流程

flowchart LR
    A["Claude Code<br/>修改文件"] --> B{"PreToolUse Hook<br/>源文件变更?"}
    B -->|"是"| C["提示: 确认测试存在"]
    B -->|"否(测试文件)"| D["正常执行"]
    C --> D
    D --> E["文件写入完成"]
    E --> F["PostToolUse Hook<br/>自动运行测试"]
    F --> G{"测试通过?"}
    G -->|"✅ 通过"| H["继续下一个任务"]
    G -->|"❌ 失败"| I["输出失败详情<br/>Claude Code 自动修复"]
    I --> A

5.4 更精细的 Hook:按文件类型分别处理

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "sh -c 'FILE=\"$CLAUDE_FILE_PATH\"; if echo \"$FILE\" | grep -q \"\\.test\\.\\|\\.spec\\.\"; then echo \"🧪 Test file modified, running related tests...\"; npx vitest run \"$FILE\" 2>&1 | tail -15; else SRC=\"${FILE%.ts}.test.ts\"; if [ -f \"$SRC\" ]; then echo \"📦 Source modified, running its tests...\"; npx vitest run \"$SRC\" 2>&1 | tail -15; fi; fi'"
          }
        ]
      }
    ]
  }
}

这个 Hook 做到了: - 如果修改的是测试文件 → 只运行该测试文件 - 如果修改的是源文件 → 自动找到对应测试文件并运行 - 其他文件修改 → 不触发测试


六、实战案例:用 TDD 构建任务管理 API

6.1 项目概述

我们将用 Claude Code 的 TDD 工作流构建一个 Task Manager REST API,包含以下功能:

6.2 Step 1:初始化项目

mkdir task-manager-api && cd task-manager-api
git init
npm init -y
npm install express zod uuid
npm install -D vitest typescript @types/express @types/uuid tsx

# 创建 Claude Code 配置
claude /init

6.3 Step 2:配置 CLAUDE.md 测试规则

将前面第三节的 CLAUDE.md 测试规则配置写入项目的 CLAUDE.md,并追加项目特定内容:

# Project: Task Manager API

## Architecture
- Language: TypeScript
- Framework: Express.js
- Validation: Zod schemas
- Testing: Vitest
- Source structure:
  ```
  src/
    models/       # Data models and types
    services/     # Business logic
    routes/       # Express route handlers
    validators/   # Zod schemas
    errors/       # Custom error classes
  ```

## Test Strategy
- Unit tests: services, validators, models
- Integration tests: routes (using supertest-like approach)
- Each service method gets its own describe block
- Use dependency injection for testability

6.4 Step 3:TDD 实战 — 创建任务功能

启动 Claude Code 并触发 TDD Skill:

claude "/tdd 实现创建任务功能:POST /api/tasks,接受 title(必填)、description(可选)、priority(low/medium/high, 默认medium)、dueDate(可选ISO日期),返回创建的task对象"

Claude Code 的完整执行过程:

Phase 1 — RED 🔴

Claude Code 首先创建测试文件 src/services/task.service.test.ts:

import { describe, it, expect, beforeEach } from 'vitest';
import { TaskService } from './task.service';
import { TaskRepository } from '../repositories/task.repository';

describe('TaskService - createTask', () => {
  let taskService: TaskService;
  let mockRepository: TaskRepository;

  beforeEach(() => {
    mockRepository = {
      save: vi.fn(),
      findById: vi.fn(),
      findAll: vi.fn(),
      delete: vi.fn(),
    } as unknown as TaskRepository;
    taskService = new TaskService(mockRepository);
  });

  it('should create a task with required fields only', async () => {
    const input = { title: 'Buy groceries' };
    mockRepository.save = vi.fn().mockResolvedValue({
      id: 'task-1',
      title: 'Buy groceries',
      description: null,
      priority: 'medium',
      status: 'todo',
      dueDate: null,
      createdAt: new Date(),
    });

    const result = await taskService.createTask(input);

    expect(result.title).toBe('Buy groceries');
    expect(result.priority).toBe('medium');
    expect(result.status).toBe('todo');
    expect(mockRepository.save).toHaveBeenCalledOnce();
  });

  it('should create a task with all fields', async () => {
    const input = {
      title: 'Write report',
      description: 'Q4 financial report',
      priority: 'high' as const,
      dueDate: '2026-07-15',
    };
    mockRepository.save = vi.fn().mockResolvedValue({
      id: 'task-2',
      ...input,
      status: 'todo',
      createdAt: new Date(),
    });

    const result = await taskService.createTask(input);

    expect(result.title).toBe('Write report');
    expect(result.priority).toBe('high');
    expect(result.dueDate).toBe('2026-07-15');
  });

  it('should reject empty title', async () => {
    const input = { title: '' };

    await expect(taskService.createTask(input)).rejects.toThrow(
      'Title is required'
    );
  });

  it('should reject invalid priority value', async () => {
    const input = { title: 'Test', priority: 'urgent' };

    await expect(taskService.createTask(input)).rejects.toThrow();
  });

  it('should reject past due dates', async () => {
    const input = { title: 'Test', dueDate: '2020-01-01' };

    await expect(taskService.createTask(input)).rejects.toThrow(
      'Due date must be in the future'
    );
  });
});

Claude Code 运行测试:

npx vitest run src/services/task.service.test.ts

输出:

❯ npx vitest run src/services/task.service.test.ts

 FAIL  src/services/task.service.test.ts
  TaskService - createTask
    ✗ should create a task with required fields only
    ✗ should create a task with all fields
    ✗ should reject empty title
    ✗ should reject invalid priority value
    ✗ should reject past due dates

🔴 RED: 5 tests failing as expected (module not found)

Phase 2 — GREEN 🟢

Claude Code 创建最小实现文件:

src/models/task.types.ts:

export type Priority = 'low' | 'medium' | 'high';
export type Status = 'todo' | 'in_progress' | 'done';

export interface Task {
  id: string;
  title: string;
  description: string | null;
  priority: Priority;
  status: Status;
  dueDate: string | null;
  createdAt: Date;
}

export interface CreateTaskInput {
  title: string;
  description?: string;
  priority?: Priority;
  dueDate?: string;
}

src/repositories/task.repository.ts:

import { Task } from '../models/task.types';

export interface TaskRepository {
  save(task: Omit<Task, 'id' | 'createdAt'>): Promise<Task>;
  findById(id: string): Promise<Task | null>;
  findAll(filter?: Record<string, unknown>): Promise<Task[]>;
  delete(id: string): Promise<boolean>;
}

src/services/task.service.ts:

import { v4 as uuidv4 } from 'uuid';
import { TaskRepository } from '../repositories/task.repository';
import { CreateTaskInput, Priority, Task } from '../models/task.types';

export class TaskService {
  constructor(private repo: TaskRepository) {}

  async createTask(input: CreateTaskInput): Promise<Task> {
    // Validate title
    if (!input.title || input.title.trim() === '') {
      throw new Error('Title is required');
    }

    // Validate priority
    const validPriorities: Priority[] = ['low', 'medium', 'high'];
    const priority = input.priority ?? 'medium';
    if (!validPriorities.includes(priority)) {
      throw new Error(`Invalid priority: ${input.priority}`);
    }

    // Validate due date
    if (input.dueDate) {
      const dueDate = new Date(input.dueDate);
      if (dueDate <= new Date()) {
        throw new Error('Due date must be in the future');
      }
    }

    const task: Task = {
      id: uuidv4(),
      title: input.title,
      description: input.description ?? null,
      priority,
      status: 'todo',
      dueDate: input.dueDate ?? null,
      createdAt: new Date(),
    };

    return this.repo.save(task);
  }
}

运行测试:

✅ GREEN: All 5 tests passing

Phase 3 — REFACTOR ♻️

Claude Code 检查代码并提出改进:

// 重构:提取验证逻辑到独立模块
// src/validators/task.validator.ts
import { Priority } from '../models/task.types';

const VALID_PRIORITIES: Priority[] = ['low', 'medium', 'high'];

export function validateTitle(title: string): void {
  if (!title || title.trim() === '') {
    throw new Error('Title is required');
  }
}

export function validatePriority(priority: string): Priority {
  if (!VALID_PRIORITIES.includes(priority as Priority)) {
    throw new Error(`Invalid priority: ${priority}`);
  }
  return priority as Priority;
}

export function validateDueDate(dateStr: string): void {
  const dueDate = new Date(dateStr);
  if (dueDate <= new Date()) {
    throw new Error('Due date must be in the future');
  }
}

重构后 TaskService 变得更简洁:

export class TaskService {
  constructor(private repo: TaskRepository) {}

  async createTask(input: CreateTaskInput): Promise<Task> {
    validateTitle(input.title);
    const priority = input.priority
      ? validatePriority(input.priority)
      : 'medium';
    if (input.dueDate) validateDueDate(input.dueDate);

    const task: Task = {
      id: uuidv4(),
      title: input.title,
      description: input.description ?? null,
      priority,
      status: 'todo',
      dueDate: input.dueDate ?? null,
      createdAt: new Date(),
    };

    return this.repo.save(task);
  }
}

每次重构后自动运行测试 → 全部通过 → ♻️ REFACTOR: 提取验证逻辑到独立模块,TaskService 职责更单一

6.5 Step 4:继续 TDD — 更多功能

按照相同模式,逐一用 TDD 实现剩余功能:

# 查询功能
claude "/tdd 实现查询任务列表:GET /api/tasks,支持 status 过滤和 page/limit 分页"

# 状态更新
claude "/tdd 实现任务状态流转:PATCH /api/tasks/:id/status,只允许 todo→in_progress→done 的正向流转"

# 删除功能
claude "/tdd 实现删除任务:DELETE /api/tasks/:id,返回204,任务不存在返回404"

# 过期检测
claude "/tdd 实现过期自动标记:系统检查到期日已过的任务,将其标记为expired状态"

6.6 项目最终结构

task-manager-api/
├── CLAUDE.md                    # TDD规则 + 项目约定
├── .claude/
│   ├── settings.json            # Hooks配置
│   └── skills/
│       └── tdd.md               # 自定义TDD Skill
├── src/
│   ├── models/
│   │   ├── task.types.ts
│   │   └── task.types.test.ts
│   ├── services/
│   │   ├── task.service.ts
│   │   └── task.service.test.ts
│   ├── validators/
│   │   ├── task.validator.ts
│   │   └── task.validator.test.ts
│   ├── routes/
│   │   ├── task.routes.ts
│   │   └── task.routes.test.ts
│   └── errors/
│       └── app-error.ts
├── package.json
├── vitest.config.ts
└── tsconfig.json

七、高级技巧:让 TDD 更高效的五种模式

7.1 模式一:测试先行提示模板

与其每次都解释需求,不如创建一个标准化的提示模板:

<!-- .claude/skills/tdd-feature.md -->
---
name: tdd-feature
description: Start TDD for a new feature with structured requirements
---

Implement the following feature using strict TDD:

## Feature: {{FEATURE_NAME}}

### Acceptance Criteria:
{{ACCEPTANCE_CRITERIA}}

### Test Cases to Cover:
1. Happy path: {{HAPPY_PATH}}
2. Edge cases: {{EDGE_CASES}}
3. Error paths: {{ERROR_PATHS}}

### Technical Notes:
- Follow existing patterns in the codebase
- Run `npx vitest run` after each phase
- Use dependency injection for testability

使用方式:

claude "/tdd-feature FEATURE_NAME='用户密码重置' ACCEPTANCE_CRITERIA='输入邮箱发送重置链接,链接24小时有效' HAPPY_PATH='已注册邮箱收到重置邮件' EDGE_CASES='未注册邮箱返回相同响应防止枚举' ERROR_PATHS='无效邮箱格式, 请求频率超限'"

7.2 模式二:/review + /verify 双重验证

Claude Code 内置两个强大的代码审查命令,在 TDD 流程中配合使用:

# /review:对当前 git diff 做代码审查
claude "/review"

# /verify:运行应用并实际验证功能是否正常
claude "/verify"

# 组合使用:TDD 完成一个功能后
claude "我刚用TDD完成了密码重置功能,请先 /review 我的代码变更,然后 /verify 确认功能正常"

7.3 模式三:覆盖率驱动的迭代

# 先检查当前覆盖率
claude "运行 npx vitest run --coverage 并分析覆盖率报告,找出覆盖率低于80%的模块"

# 针对性补充测试
claude "/tdd 为覆盖率不足的模块补充测试,优先覆盖未测试的分支"

7.4 模式四:Bug 修复也走 TDD

Bug 修复是最容易跳过测试的场景,但恰恰最需要 TDD:

claude "/tdd 修复以下bug:当用户创建任务时不填priority字段,返回500错误而不是使用默认值medium。

复现步骤:
1. POST /api/tasks body: {title: 'test'}
2. 期望返回 priority: 'medium'
3. 实际返回 500 Internal Server Error

先写一个能复现该bug的测试(RED),然后修复代码(GREEN),最后确认没有引入回归(REFACTOR)。"

7.5 模式五:批量化 TDD 与进度追踪

对于需要一次性实现多个功能的场景:

# 使用 TaskCreate 创建任务列表
claude "分析以下需求文档(requirements.md),用 /tdd 逐个实现每个功能点,每完成一个就运行测试确认,然后标记完成并继续下一个"
flowchart TD
    A["需求文档"] --> B["Claude Code 拆分功能点"]
    B --> C["功能1: TDD循环"]
    C --> D["功能2: TDD循环"]
    D --> E["功能3: TDD循环"]
    E --> F["功能N: TDD循环"]
    F --> G["全量测试"]
    G --> H{"覆盖率 ≥ 80%?"}
    H -->|"是"| I["✅ 完成"]
    H -->|"否"| J["补充测试"]
    J --> G

    subgraph "每个TDD循环"
        C1["🔴 RED"] --> C2["🟢 GREEN"] --> C3["♻️ REFACTOR"]
    end

八、常见问题与解决方案

Q1:Claude Code 还是先写了实现怎么办?

根因:CLAUDE.md 的 TDD 规则可能被更急迫的上下文"淹没"。

解决方案: 1. 确保 TDD 规则在 CLAUDE.md 的最前面 2. 使用自定义 Skill(/tdd)而非自然语言指令 3. 在 Hook 中增加硬性阻断:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [{
          "type": "command",
          "command": "sh -c 'FILE=\"$CLAUDE_FILE_PATH\"; if echo \"$FILE\" | grep -qv \"\\.test\\.\\|\\.spec\\.\\|CLAUDE\\|settings\"; then TESTFILE=$(echo \"$FILE\" | sed \"s/\\.ts$/.test.ts/\"); if [ ! -f \"$TESTFILE\" ]; then echo \"⛔ BLOCKED: No test file found for $FILE. Create $TESTFILE first.\"; exit 1; fi; fi'"
        }]
      }
    ]
  }
}

这个 Hook 会阻止 Claude Code 创建源文件——除非对应的测试文件已经存在。

Q2:AI 生成的测试质量低怎么办?

解决方案:在 CLAUDE.md 中增加具体的测试质量标准:

## Test Quality Checklist (Claude MUST verify before submitting)
- [ ] Test name describes expected behavior, not implementation
- [ ] Arrange-Act-Assert pattern is clear
- [ ] No hardcoded dates or IDs — use factories/fixtures
- [ ] Mocks only for external dependencies, not for domain logic
- [ ] Edge cases covered: empty input, null, undefined, boundary values
- [ ] Error messages are asserted, not just error types

Q3:TDD 太慢,影响开发效率?

平衡策略:不是所有代码都需要严格 TDD。在 CLAUDE.md 中明确分级:

## TDD Enforcement Levels
- **Level 3 (Strict)**: Business logic, payment, auth, data transformation → Full Red-Green-Refactor
- **Level 2 (Standard)**: API routes, middleware, data access → Test + Implement together
- **Level 1 (Light)**: Config files, types, constants → No test required

Q4:如何在已有项目中引入 TDD?

渐进式策略:

# 第一步:只为新增代码强制 TDD
claude "分析当前代码库中哪些模块有测试、哪些没有。为新功能开发制定 TDD 规则,存量代码暂不要求。"

# 第二步:逐步为高风险模块补测试
claude "/tdd 为 src/services/payment.service.ts 补充测试,它处理支付逻辑但目前0测试覆盖"

# 第三步:设置覆盖率基线,只升不降
# 在 vitest.config.ts 中配置:
# coverage: { thresholds: { lines: 60, branches: 50, functions: 60 } }

九、TDD 全流程架构总览

graph TB
    subgraph "用户输入"
        REQ["功能需求 / Bug描述"]
    end

    subgraph "Claude Code TDD 引擎"
        SKILL["/tdd Skill<br/>流程编排"]
        RED["🔴 RED Phase<br/>生成测试代码"]
        GREEN["🟢 GREEN Phase<br/>最小实现"]
        REFACTOR["♻️ REFACTOR Phase<br/>代码改进"]
    end

    subgraph "三层防线"
        CMD["CLAUDE.md<br/>测试规则"]
        HOOK["Hooks<br/>自动守门"]
        REVIEW["/review + /verify<br/>质量审查"]
    end

    subgraph "测试基础设施"
        VITEST["Vitest<br/>测试运行器"]
        COV["Coverage<br/>覆盖率报告"]
        CI["CI Pipeline<br/>持续集成"]
    end

    REQ --> SKILL
    CMD --> SKILL
    SKILL --> RED
    RED -->|"测试失败"| GREEN
    GREEN -->|"测试通过"| REFACTOR
    REFACTOR -->|"测试仍通过"| REVIEW
    HOOK -->|"每次文件变更触发"| VITEST
    REVIEW --> VITEST
    VITEST --> COV
    COV --> CI

    style RED fill:#ffcccc,stroke:#cc0000
    style GREEN fill:#ccffcc,stroke:#00cc00
    style REFACTOR fill:#ccccff,stroke:#0000cc
    style CMD fill:#fff3cd,stroke:#856404
    style HOOK fill:#d4edda,stroke:#155724
    style REVIEW fill:#cce5ff,stroke:#004085

十、不同语言/框架的 TDD 配置速查

Python + pytest

# CLAUDE.md testing section (Python version)
## Test Commands
- Run all: `pytest`
- Run single: `pytest tests/test_feature.py -v`
- Coverage: `pytest --cov=src --cov-report=term-missing`

## Conventions
- Test files: `tests/test_*.py`
- Fixtures in `tests/conftest.py`
- Use `pytest.raises` for exception testing
- Factory pattern with `factory_boy` for test data

Go + testing

# CLAUDE.md testing section (Go version)
## Test Commands
- Run all: `go test ./...`
- Run single: `go test ./pkg/service -v`
- Coverage: `go test -cover ./...`
- Race detection: `go test -race ./...`

## Conventions
- Test files: `*_test.go` in same package
- Table-driven tests using `t.Run`
- Use `testify/assert` for readable assertions
- Interfaces for dependency injection

延伸阅读

资源 说明
Anthropic 官方 Claude Code 文档 Slash Commands、Hooks、Skills 完整参考
Claude Code Hooks 官方指南 所有生命周期钩子的详细说明
Claude Code TDD Skill 实战 作者 Alexander Op 细致的 Skill 编写教程
Claude Code 测试生成实践指南 CLAUDE.md 规则 + Hooks + TDD 三层体系
Claude Code TDD Skill 实现 具体的 Skill 代码和执行流程
Claude Code 命令速查表 70+ slash commands 和 CLI flags 完整清单

训练营适用性评估

评估维度 说明
适用训练营类型 AI 辅助开发训练营、高级软件工程训练营、质量工程实战营
学员基础要求 TypeScript/Python 基础 + Claude Code 入门经验 + 了解单元测试概念
预计教学时长 4-6 小时(含动手实操)
推荐教学节奏 第1小时:理论+CLAUDE.md配置 → 第2-3小时:TDD Skill+Hooks实操 → 第4-5小时:完整项目实战 → 第6小时:回顾+Q&A
硬件要求 每人一台笔记本,已安装 Claude Code + Node.js + Git
分组建议 2-3人一组,一人写需求/验收,一人操作 Claude Code,一人审查输出

参考来源

  1. A Claude Code TDD Skill: Forcing Red-Green-Refactor Discipline — alexop.dev — 自定义 TDD Skill 的完整实现,包含 Skill 代码和执行效果
  2. Claude Code Test Generation: A Practical Guide — 32blog — CLAUDE.md 测试规则、Hooks 自动化、TDD 工作流三层体系实践指南
  3. How to Implement TDD with Claude Code TDD Skill — BSWEN — Claude Code TDD Skill 的配置方法和使用流程
  4. Claude Code Cheat Sheet — ComputingForGeeks — Claude Code 2.1.x 全命令速查,包含 Slash Commands 和 Hooks 参考
  5. Automate Actions with Hooks — Claude Code Official Docs — Anthropic 官方 Hooks 生命周期和配置文档

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入