<!-- title: Claude Code测试驱动与质量门禁实战 -->

# Claude Code 测试驱动开发与质量门禁全实战

## 概述

本教程面向已掌握 Claude Code 基础操作的中级开发者，系统讲解如何将测试驱动开发（TDD）理念与 Claude Code 的 AI 辅助编程深度结合，构建从单测编写到质量门禁的完整自动化体系。学完本教程，你将掌握 Red-Green-Refactor 循环在 AI 时代的最佳实践、Claude Code 原生 TDD Skill 的配置与扩展、Hooks 驱动的质量门禁搭建，以及如何在团队中落地可复用的测试工作流。

**适用人群**：有 3 个月以上 Claude Code 使用经验、熟悉至少一种测试框架（Jest/Vitest/pytest 等）的开发者。

**学习目标**：
- 理解 AI 辅助 TDD 的核心循环与反模式
- 配置并扩展 Claude Code 内置 TDD Skill
- 用 Hooks 构建多层质量门禁
- 完成一个可运行的 TDD 实战项目

---

## 前置条件

| 工具/知识 | 最低要求 |
|-----------|---------|
| Claude Code | ≥ 1.0.18（支持 Skills 和 Hooks） |
| Node.js | ≥ 18.x（本教程使用 Vitest） |
| Git | ≥ 2.30 |
| 测试框架基础 | 了解 describe/it/expect 模式 |
| Claude Code 基础 | 会使用 `/init`、`/compact`、CLAUDE.md |

**环境准备**：

```bash
# 创建项目目录
mkdir tdd-with-claude && cd tdd-with-claude

# 初始化 Node 项目
npm init -y

# 安装 Vitest
npm install -D vitest

# 初始化 Claude Code 配置
claude init

# 验证 Claude Code 版本
claude --version
```

---

## 第一章：AI 时代的 TDD——为什么传统模式需要升级

### 1.1 传统 TDD 的痛点

传统 TDD 循环是 **Red → Green → Refactor**：先写一个失败的测试，写最少代码让测试通过，然后重构。但在实践中，开发者经常遇到三个瓶颈：

- **测试编写耗时**：写测试的时间往往超过写业务代码
- **重构信心不足**：不敢重构，怕破坏已有测试
- **覆盖率假象**：追求 100% 覆盖率却遗漏边界条件

### 1.2 Claude Code 如何改变游戏规则

Claude Code 不是替代 TDD，而是**加速 TDD 每个环节**：

```mermaid
flowchart LR
    subgraph 传统TDD
        T1[手写测试] --> T2[手写实现] --> T3[手动重构]
    end
    subgraph AI辅助TDD
        A1["描述测试意图<br/>Claude生成测试代码"] --> A2["Claude快速实现<br/>最小可行代码"] --> A3["Claude识别异味<br/>建议安全重构"]
    end
    传统TDD -.->|耗时比 3:1:2| AI辅助TDD
    style AI辅助TDD fill:#e8f5e9
```

关键区别：在 AI 辅助 TDD 中，你的角色从"写代码的人"变成"设计测试的人"。你定义**测试意图**（测试什么、边界在哪），Claude Code 负责**代码生成**（怎么测、怎么实现）。

### 1.3 核心原则：人定意图，AI 定实现

这不是让 Claude 替你写一切。核心纪律是：

| 环节 | 人的职责 | Claude Code 的职责 |
|------|---------|-------------------|
| Red | 定义测试场景、边界条件 | 生成测试代码骨架 |
| Green | 确认测试意图正确 | 生成最小实现代码 |
| Refactor | 判断重构方向 | 执行重构、保持测试通过 |
| Review | 审查测试质量 | 检测遗漏场景、建议改进 |

---

## 第二章：项目配置——为 TDD 打造 Claude Code 环境

### 2.1 CLAUDE.md 中的 TDD 指令

在项目根目录的 `CLAUDE.md` 中添加 TDD 工作规范：

```markdown
# TDD 工作规范

## 开发纪律
- 所有新功能必须先写测试，再写实现（Red-Green-Refactor）
- 测试文件放在 `src/` 同级目录，命名为 `*.test.ts`
- 使用 Vitest 作为测试框架
- 每次修改代码后必须运行相关测试验证

## 测试要求
- 每个公开函数至少 3 个测试：正常路径、边界条件、错误处理
- 测试描述使用中文，说明测试意图
- 使用 `describe` 按功能分组，`it` 描述具体场景
- Mock 外部依赖，不 Mock 被测模块内部函数

## 质量标准
- 测试覆盖率不低于 80%
- 所有测试必须在 10 秒内完成
- 禁止使用 `any` 类型
```

**为什么要在 CLAUDE.md 写这些？** 因为 Claude Code 每次启动会话时自动读取这个文件。把 TDD 纪律写在这里，等于给 Claude Code 一个**持久的行为约束**——它不会跳过测试直接写实现。

### 2.2 项目结构设计

```
tdd-with-claude/
├── .claude/
│   ├── commands/          # 自定义 Slash Commands
│   │   ├── tdd-red.md     # TDD Red 阶段命令
│   │   ├── tdd-green.md   # TDD Green 阶段命令
│   │   └── tdd-refactor.md # TDD Refactor 阶段命令
│   ├── rules/             # 项目规则
│   │   └── testing.md     # 测试规则详情
│   ├── settings.json      # Hooks 和权限配置
│   └── skills/            # 自定义 Skills
├── src/
│   ├── calculator.ts
│   ├── calculator.test.ts
│   ├── validator.ts
│   └── validator.test.ts
├── CLAUDE.md
├── vitest.config.ts
└── package.json
```

### 2.3 Vitest 配置

```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    coverage: {
      provider: 'v8',
      reporter: ['text', 'html', 'json-summary'],
      include: ['src/**/*.ts'],
      exclude: ['src/**/*.test.ts'],
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 75,
        statements: 80,
      },
    },
    testTimeout: 10000,
    hookTimeout: 10000,
  },
});
```

---

## 第三章：三个 TDD Slash Commands——让纪律成为命令

这是本教程的核心创新：将 TDD 的三个阶段分别封装为 Claude Code 自定义 Slash Commands。

### 3.1 `/tdd-red`：生成测试命令

创建 `.claude/commands/tdd-red.md`：

```markdown
# TDD Red Phase - 测试先行

你正在执行 TDD 的 Red 阶段。根据以下规则生成测试：

## 输入
用户会描述要测试的功能。参数: $ARGUMENTS

## 你的任务
1. 分析功能需求，识别所有测试场景
2. 为每个场景生成一个测试用例
3. 确保覆盖：正常路径、边界条件、错误处理
4. **不要**生成任何实现代码，只生成测试

## 测试模板
```typescript
import { describe, it, expect } from 'vitest';

describe('功能名称', () => {
  it('应该在正常输入时返回预期结果', () => {
    // Arrange - 准备测试数据
    // Act - 执行被测函数
    // Assert - 验证结果
  });

  it('应该在边界条件时正确处理', () => {
    // ...
  });

  it('应该在错误输入时抛出异常', () => {
    // ...
  });
});
```

## 输出要求
- 只输出测试文件内容
- 测试描述使用中文
- 文件命名为 `src/<模块名>.test.ts`
- 生成后运行测试，确认全部失败（Red 状态）
- 报告生成的测试数量和预期失败数
```

### 3.2 `/tdd-green`：最小实现命令

创建 `.claude/commands/tdd-green.md`：

```markdown
# TDD Green Phase - 最小实现

你正在执行 TDD 的 Green 阶段。

## 输入
参数: $ARGUMENTS（要实现的模块名）

## 你的任务
1. 读取对应的测试文件 `src/$ARGUMENTS.test.ts`
2. 分析所有失败的测试用例
3. 编写**最少**的代码让所有测试通过
4. 不要过度设计，不要添加测试未要求的功能

## 纪律要求
- 只写让测试通过的最少代码
- 允许硬编码值（Refactor 阶段再优化）
- 不要添加额外的错误处理（除非测试要求）
- 不要添加日志、注释等非必要代码

## 验证步骤
1. 写完实现后立即运行 `npx vitest run src/$ARGUMENTS.test.ts`
2. 如果测试全部通过，报告 Green 状态
3. 如果有测试失败，修改实现直到全部通过
4. 最后运行覆盖率报告
```

### 3.3 `/tdd-refactor`：安全重构命令

创建 `.claude/commands/tdd-refactor.md`：

```markdown
# TDD Refactor Phase - 安全重构

你正在执行 TDD 的 Refactor 阶段。

## 输入
参数: $ARGUMENTS（要重构的模块名）

## 你的任务
1. 读取 `src/$ARGUMENTS.ts` 和 `src/$ARGUMENTS.test.ts`
2. 识别代码异味和改进机会：
   - 重复代码
   - 过长的函数
   - 命名不清晰
   - 可以简化的逻辑
   - 缺少类型安全
3. 执行重构，**保持所有测试通过**

## 重构纪律
- 每次只做一种重构
- 每次重构后都运行测试
- 如果测试失败，立即回滚
- 不改变公开 API

## 验证步骤
1. 重构前运行测试，记录基线
2. 执行重构
3. 重构后运行测试，确认全部通过
4. 运行覆盖率报告，确认未降低
5. 列出所有重构操作和改进点
```

### 3.4 使用方式

```bash
# 在 Claude Code 会话中：

# 步骤 1: 描述功能，生成测试（Red）
/tdd-red calculator 四则运算计算器，支持加减乘除，处理除零错误和溢出

# 步骤 2: 让 Claude 写最小实现（Green）
/tdd-green calculator

# 步骤 3: 让 Claude 安全重构（Refactor）
/tdd-refactor calculator
```

---

## 第四章：实战项目——用 TDD 构建表达式求值器

现在用一个完整项目演示整个流程。我们要构建一个**数学表达式求值器**，支持四则运算、括号和变量。

### 4.1 Red 阶段：定义测试

在 Claude Code 中输入：

```
/tdd-red evaluator 数学表达式求值器：
1. 支持加减乘除四则运算
2. 支持括号改变优先级
3. 支持变量赋值和使用（x = 5, x + 3）
4. 除零时抛出 DivisionByZeroError
5. 非法表达式时抛出 SyntaxError
```

Claude Code 会生成类似以下测试：

```typescript
// src/evaluator.test.ts
import { describe, it, expect } from 'vitest';
import { evaluate, Evaluator } from './evaluator';

describe('表达式求值器', () => {
  describe('基本四则运算', () => {
    it('应该正确计算加法', () => {
      expect(evaluate('2 + 3')).toBe(5);
    });

    it('应该正确计算减法', () => {
      expect(evaluate('10 - 4')).toBe(6);
    });

    it('应该正确计算乘法', () => {
      expect(evaluate('3 * 7')).toBe(21);
    });

    it('应该正确计算除法', () => {
      expect(evaluate('15 / 3')).toBe(5);
    });

    it('应该正确处理运算优先级', () => {
      expect(evaluate('2 + 3 * 4')).toBe(14);
    });

    it('应该正确处理浮点数', () => {
      expect(evaluate('1.5 + 2.5')).toBe(4);
    });
  });

  describe('括号支持', () => {
    it('应该用括号改变优先级', () => {
      expect(evaluate('(2 + 3) * 4')).toBe(20);
    });

    it('应该支持嵌套括号', () => {
      expect(evaluate('((1 + 2) * (3 + 4))')).toBe(21);
    });

    it('应该检测不匹配的括号', () => {
      expect(() => evaluate('(2 + 3')).toThrow(SyntaxError);
    });
  });

  describe('变量支持', () => {
    it('应该支持变量赋值和使用', () => {
      const ev = new Evaluator();
      ev.setVariable('x', 5);
      expect(ev.evaluate('x + 3')).toBe(8);
    });

    it('应该在使用未定义变量时抛出错误', () => {
      const ev = new Evaluator();
      expect(() => ev.evaluate('y + 1')).toThrow();
    });
  });

  describe('错误处理', () => {
    it('应该在除零时抛出 DivisionByZeroError', () => {
      expect(() => evaluate('10 / 0')).toThrow();
    });

    it('应该在非法表达式时抛出 SyntaxError', () => {
      expect(() => evaluate('2 + + 3')).toThrow(SyntaxError);
    });

    it('应该在空输入时抛出 SyntaxError', () => {
      expect(() => evaluate('')).toThrow(SyntaxError);
    });
  });
});
```

运行测试确认全部失败：

```bash
npx vitest run src/evaluator.test.ts
```

**预期结果**：所有测试失败（Red 状态），因为 `evaluator.ts` 尚不存在。

### 4.2 Green 阶段：最小实现

```
/tdd-green evaluator
```

Claude Code 会生成最小实现：

```typescript
// src/evaluator.ts
export class DivisionByZeroError extends Error {
  constructor() {
    super('Division by zero');
    this.name = 'DivisionByZeroError';
  }
}

export class Evaluator {
  private variables: Map<string, number> = new Map();

  setVariable(name: string, value: number): void {
    this.variables.set(name, value);
  }

  evaluate(expression: string): number {
    if (!expression.trim()) {
      throw new SyntaxError('Empty expression');
    }
    // 替换变量
    let expr = expression;
    for (const [name, value] of this.variables) {
      expr = expr.replace(new RegExp(`\\b${name}\\b`, 'g'), String(value));
    }
    // 检测未定义变量（裸字母）
    if (/[a-zA-Z_]\w*/g.test(expr.replace(/\b(sin|cos|tan|log)\b/g, ''))) {
      const remaining = expr.match(/\b[a-zA-Z_]\w*\b/g);
      if (remaining) {
        throw new Error(`Undefined variable: ${remaining[0]}`);
      }
    }
    return this.parseExpression(expr);
  }

  private parseExpression(expr: string): number {
    try {
      // 安全的数学表达式解析
      const tokens = this.tokenize(expr);
      const result = this.parseAddSub(tokens, 0);
      if (tokens[result.index] !== undefined) {
        throw new SyntaxError(`Unexpected token: ${tokens[result.index]}`);
      }
      return result.value;
    } catch (e) {
      if (e instanceof DivisionByZeroError || e instanceof SyntaxError) throw e;
      throw new SyntaxError(`Invalid expression: ${expr}`);
    }
  }

  private tokenize(expr: string): string[] {
    return expr.match(/(\d+\.?\d*|[+\-*/()])/g) || [];
  }

  private parseAddSub(tokens: string[], pos: number): { value: number; index: number } {
    let left = this.parseMulDiv(tokens, pos);
    while (tokens[left.index] === '+' || tokens[left.index] === '-') {
      const op = tokens[left.index];
      const right = this.parseMulDiv(tokens, left.index + 1);
      left = {
        value: op === '+' ? left.value + right.value : left.value - right.value,
        index: right.index,
      };
    }
    return left;
  }

  private parseMulDiv(tokens: string[], pos: number): { value: number; index: number } {
    let left = this.parsePrimary(tokens, pos);
    while (tokens[left.index] === '*' || tokens[left.index] === '/') {
      const op = tokens[left.index];
      const right = this.parsePrimary(tokens, left.index + 1);
      if (op === '/' && right.value === 0) throw new DivisionByZeroError();
      left = {
        value: op === '*' ? left.value * right.value : left.value / right.value,
        index: right.index,
      };
    }
    return left;
  }

  private parsePrimary(tokens: string[], pos: number): { value: number; index: number } {
    if (tokens[pos] === '(') {
      const result = this.parseAddSub(tokens, pos + 1);
      if (tokens[result.index] !== ')') {
        throw new SyntaxError('Mismatched parentheses');
      }
      return { value: result.value, index: result.index + 1 };
    }
    const num = parseFloat(tokens[pos]);
    if (isNaN(num)) {
      throw new SyntaxError(`Unexpected token: ${tokens[pos]}`);
    }
    return { value: num, index: pos + 1 };
  }
}

export function evaluate(expression: string): number {
  return new Evaluator().evaluate(expression);
}
```

运行测试：

```bash
npx vitest run src/evaluator.test.ts
```

**预期结果**：所有测试通过（Green 状态）。

### 4.3 Refactor 阶段：安全重构

```
/tdd-refactor evaluator
```

Claude Code 会分析代码并提出重构建议。典型操作包括：
- 提取 `TokenType` 枚举增强可读性
- 将解析逻辑拆分为独立的 `Parser` 类
- 添加更精确的错误位置信息
- 使用迭代器模式替代索引传递

每次重构后自动运行测试验证。

---

## 第五章：Hooks 驱动的质量门禁

### 5.1 质量门禁架构

```mermaid
flowchart TB
    subgraph 质量门禁层
        direction TB
        L1["第一层：PreToolUse<br/>写文件前自动格式化"]
        L2["第二层：PostToolUse<br/>修改代码后自动检查"]
        L3["第三层：Notification<br/>测试失败时告警"]
    end

    Dev[开发者操作] --> L1
    L1 --> L2
    L2 --> L3
    L3 --> Pass{通过?}
    Pass -->|是| OK[代码就绪]
    Pass -->|否| Fix[显示修复建议]

    style L1 fill:#fff3e0
    style L2 fill:#e3f2fd
    style L3 fill:#fce4ec
```

### 5.2 配置 Hooks

在 `.claude/settings.json` 中配置质量门禁 Hooks：

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      },
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "FILE=\"$CLAUDE_FILE_PATH\"; if [[ \"$FILE\" == src/*.ts && \"$FILE\" != *.test.ts && \"$FILE\" != *.d.ts ]]; then TEST_FILE=\"${FILE%.ts}.test.ts\"; if [ -f \"$TEST_FILE\" ]; then npx vitest run \"$TEST_FILE\" --reporter=verbose 2>&1 | tail -20; fi; fi"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "FILE=\"$CLAUDE_FILE_PATH\"; if [[ \"$FILE\" == *.ts && \"$FILE\" != *.test.ts ]]; then npx tsc --noEmit \"$FILE\" 2>&1 | head -10; fi"
          }
        ]
      }
    ]
  }
}
```

**三道门禁解析**：

| 层级 | Hook 类型 | 触发时机 | 作用 |
|------|----------|---------|------|
| 第一层 | PreToolUse | 写入文件前 | TypeScript 类型检查，阻止类型错误 |
| 第二层 | PostToolUse #1 | 写入文件后 | Prettier 自动格式化 |
| 第三层 | PostToolUse #2 | 写入文件后 | 自动运行关联测试 |

### 5.3 自定义质量门禁 Skill

创建 `.claude/skills/quality-gate.md`：

```markdown
---
description: 代码质量门禁检查。在代码修改完成后触发，执行完整的质量检查流程。
---

# 质量门禁 Skill

当用户完成代码修改并要求质量检查时，执行以下流程：

## 检查步骤

### 1. 类型检查
```bash
npx tsc --noEmit
```
如果有错误，列出所有类型错误并建议修复方案。

### 2. Lint 检查
```bash
npx eslint src/ --max-warnings 0
```
如果有警告或错误，按严重程度排序显示。

### 3. 测试执行
```bash
npx vitest run --coverage
```
报告测试结果和覆盖率。如果覆盖率低于阈值，指出未覆盖的行。

### 4. 测试质量审计
检查测试文件是否存在以下问题：
- 测试之间有隐式依赖（共享状态）
- 测试描述不够具体
- 缺少边界条件测试
- Mock 使用不当

### 5. 输出报告
生成结构化质量报告：
- ✅ 通过项
- ⚠️ 警告项
- ❌ 失败项
- 📊 覆盖率数据
```

---

## 第六章：进阶模式——测试生成器与回归防护

### 6.1 批量测试生成命令

创建 `.claude/commands/gen-tests.md`：

```markdown
# 批量测试生成器

为指定目录下所有源文件生成测试。

## 输入
参数: $ARGUMENTS（源文件目录，默认 src/）

## 你的任务
1. 扫描目录下的所有 `.ts` 文件（排除 `.test.ts` 和 `.d.ts`）
2. 对每个文件：
   a. 分析导出的函数/类
   b. 生成测试文件 `*.test.ts`
   c. 确保测试文件可执行
3. 运行所有生成的测试
4. 报告每个文件的测试数量和通过率

## 测试生成规则
- 每个纯函数至少 5 个测试：2 正常 + 2 边界 + 1 错误
- 每个类的方法至少 3 个测试
- 使用 AAA 模式（Arrange-Act-Assert）
- 不 Mock 被测模块的内部函数
```

### 6.2 回归测试守护命令

创建 `.claude/commands/regression-guard.md`：

```markdown
# 回归测试守护

在修改代码前快照当前测试状态，修改后对比。

## 输入
参数: $ARGUMENTS（要修改的模块名）

## 你的任务
1. 运行当前所有测试，记录基线结果
2. 用户进行代码修改
3. 修改完成后再次运行所有测试
4. 对比前后结果，报告：
   - 新增的通过测试
   - 新增的失败测试（回归）
   - 新增的跳过测试
   - 性能变化（执行时间对比）

## 回归报告格式
```
📊 回归测试报告
━━━━━━━━━━━━━━━━━━━━
基线: 42 passed, 0 failed
当前: 44 passed, 1 failed
━━━━━━━━━━━━━━━━━━━━
✅ 新增通过: 2 tests
❌ 回归: 1 test
  - src/calculator.test.ts > 除法 > 应该处理大数溢出
⏱️ 性能: +120ms (+15%)
━━━━━━━━━━━━━━━━━━━━
```
```

### 6.3 Mutation Testing 集成

Mutation Testing 是验证测试质量的终极武器——通过故意引入 Bug，检查测试是否能捕获。

```bash
# 安装 Stryker（JavaScript/TypeScript 的 Mutation Testing 框架）
npm install -D @stryker-mutator/core @stryker-mutator/vitest-runner
```

创建 `.claude/commands/mutation-test.md`：

```markdown
# Mutation Testing - 变异测试

验证测试质量，检查测试能否捕获故意引入的 Bug。

## 输入
参数: $ARGUMENTS（要变异测试的模块名）

## 你的任务
1. 安排 Stryker 配置（如未配置）
2. 对目标模块运行变异测试
3. 分析变异存活者（Survived Mutants）
4. 为每个存活变异生成补充测试
5. 重新运行变异测试验证改进效果

## 输出格式
- 变异得分（Mutation Score）
- 存活变异列表及建议的修复测试
- 改进前后的得分对比
```

---

## 第七章：团队级工作流——从个人到团队

### 7.1 共享测试规则

创建 `.claude/rules/testing.md`：

```markdown
# 测试规则

## 命名规范
- 测试文件：`<module>.test.ts`
- 测试描述：`describe` 用功能名，`it` 用中文描述场景
- 工具函数：`test-utils.ts` 或 `helpers/test-*.ts`

## 覆盖率要求
- 核心业务逻辑：≥ 90%
- 工具函数：≥ 80%
- UI 组件：≥ 60%（重点测交互逻辑）

## Mock 策略
- Mock 外部 API 调用
- Mock 文件系统和时间相关函数
- **禁止** Mock 被测模块自身的函数
- Mock 数据放在 `__mocks__/` 目录

## 禁止事项
- 禁止 `ts-ignore` / `@ts-ignore`
- 禁止使用 `as any`
- 禁止跳过测试（`xit` / `skip`）除非标注原因和 issue 号
- 禁止在测试中使用 `setTimeout` 等待
```

### 7.2 CI 集成脚本

创建 `.claude/commands/ci-check.md`：

```markdown
# CI 质量检查

模拟 CI 环境执行完整质量检查。

## 执行步骤
1. **安装依赖**: `npm ci`
2. **类型检查**: `npx tsc --noEmit`
3. **Lint**: `npx eslint src/ --max-warnings 0`
4. **单元测试**: `npx vitest run --coverage`
5. **覆盖率阈值**: 检查是否达到 80%
6. **构建验证**: `npm run build`

## 失败处理
任何步骤失败时：
- 显示详细错误信息
- 建议修复命令
- 不继续后续步骤
```

### 7.3 工作流全景图

```mermaid
flowchart TB
    subgraph 开发阶段
        A["开发者输入需求"] --> B["/tdd-red<br/>生成测试"]
        B --> C{"所有测试<br/>失败?"}
        C -->|是| D["/tdd-green<br/>最小实现"]
        C -->|否| B
        D --> E{"所有测试<br/>通过?"}
        E -->|是| F["/tdd-refactor<br/>安全重构"]
        E -->|否| D
        F --> G{"测试仍<br/>通过?"}
        G -->|是| H["/quality-gate<br/>质量门禁"]
        G -->|否| F
    end

    subgraph 质量门禁
        H --> I["类型检查"]
        I --> J["Lint 检查"]
        J --> K["测试 + 覆盖率"]
        K --> L["测试质量审计"]
    end

    subgraph 持续保障
        L --> M["提交代码"]
        M --> N["CI 自动执行"]
        N --> O["回归测试守护"]
    end

    style B fill:#ffcdd2
    style D fill:#c8e6c9
    style F fill:#bbdefb
    style H fill:#fff9c4
```

---

## 第八章：常见问题与解决方案

### 8.1 Claude Code 跳过测试直接写实现

**问题**：有时 Claude Code 会忽略 CLAUDE.md 中的 TDD 规则，直接写实现代码。

**解决方案**：在 CLAUDE.md 中增加更强的约束：

```markdown
## 强制 TDD 约束
- 如果被要求实现一个功能但对应的测试文件不存在，必须先创建测试文件
- 在写实现代码之前，先运行测试确认它们会失败
- 如果用户没有明确要求跳过 TDD，始终遵循 Red-Green-Refactor 流程
```

### 8.2 Hooks 执行缓慢影响体验

**问题**：PostToolUse Hook 每次编辑都运行测试，对于大型项目会很慢。

**解决方案**：优化 Hook 只运行受影响的测试：

```json
{
  "matcher": "Write|Edit",
  "hooks": [{
    "type": "command",
    "command": "FILE=\"$CLAUDE_FILE_PATH\"; if [[ \"$FILE\" == src/*.ts ]]; then TEST=\"${FILE%.ts}.test.ts\"; [ -f \"$TEST\" ] && npx vitest run \"$TEST\" --reporter=basic 2>&1 | tail -5; fi"
  }]
}
```

### 8.3 生成的测试质量不够高

**问题**：Claude Code 生成的测试过于简单，缺少边界条件。

**解决方案**：在 Slash Command 中增加更详细的测试模板：

```markdown
## 测试场景清单（必须逐项覆盖）
1. ✅ Happy Path — 最简单的正确输入
2. ✅ 边界值 — 最小值、最大值、零、空字符串
3. ✅ 错误输入 — null、undefined、错误类型
4. ✅ 并发/重复 — 多次调用、连续调用
5. ✅ 极端情况 — 超大数据、超深嵌套、Unicode
```

### 8.4 测试与实现之间的耦合过紧

**问题**：重构实现代码时测试大面积失败，说明测试过度依赖实现细节。

**解决方案**：使用 `.claude/rules/testing.md` 约束：

```markdown
## 测试设计原则
- 通过公开 API 测试行为，不测试内部实现
- 不断言私有方法的返回值
- 不检查函数调用次数（除非是关键副作用）
- 不依赖代码执行顺序
```

---

## 第九章：项目模板——一键初始化 TDD 项目

### 9.1 一键初始化命令

创建 `.claude/commands/init-tdd.md`：

```markdown
# TDD 项目初始化器

为当前项目配置完整的 TDD 工作流。

## 输入
参数: $ARGUMENTS（项目类型：node / react / api，默认 node）

## 执行步骤

### 1. 项目结构
创建以下目录和文件：
- `src/` — 源代码
- `src/*.test.ts` — 测试文件
- `.claude/commands/` — TDD 命令
- `.claude/rules/testing.md` — 测试规则
- `.claude/skills/quality-gate.md` — 质量门禁

### 2. 依赖安装
根据项目类型安装测试框架：
- node: `npm install -D vitest`
- react: `npm install -D vitest @testing-library/react jsdom`
- api: `npm install -D vitest supertest`

### 3. 配置文件
- 生成 `vitest.config.ts`
- 更新 `package.json` scripts
- 配置 `.claude/settings.json` Hooks

### 4. CLAUDE.md 模板
生成包含 TDD 规范的 CLAUDE.md

### 5. 示例验证
创建一个简单的示例函数和测试，验证整个流程可用

## 输出
报告已创建的文件列表和验证结果
```

### 9.2 使用模板启动新项目

```bash
# 新建项目
mkdir my-tdd-project && cd my-tdd-project
npm init -y
claude init

# 在 Claude Code 会话中
/init-tdd node
```

---

## 第十章：效果度量与持续改进

### 10.1 关键指标

| 指标 | 目标值 | 测量方式 |
|------|--------|---------|
| 测试覆盖率 | ≥ 80% | `vitest --coverage` |
| Red→Green 时间 | < 5 分钟 | 计时 Claude Code 执行 |
| 重构安全率 | 100% 测试通过 | Hooks 自动验证 |
| 测试/代码比 | 1:1 到 2:1 | 行数统计 |
| 回归捕获率 | > 95% | Mutation Testing 得分 |

### 10.2 周度回顾命令

创建 `.claude/commands/weekly-review.md`：

```markdown
# 周度测试回顾

分析本周测试工作流的效果。

## 执行步骤
1. 运行完整测试套件，记录当前状态
2. 分析覆盖率变化趋势
3. 检查是否有跳过的测试
4. 检查是否有标记为 TODO 的测试
5. 审查最近添加的测试质量
6. 生成改进建议

## 输出报告
- 📊 覆盖率趋势
- ⚠️ 待处理的测试问题
- 💡 改进建议
```

---

## 总结

本教程构建了一个完整的 **Claude Code TDD 工作流体系**：

1. **纪律层**：通过 CLAUDE.md 和 Rules 强制 TDD 规范
2. **命令层**：通过 Slash Commands 封装 Red/Green/Refactor 三阶段
3. **门禁层**：通过 Hooks 自动运行类型检查、格式化和测试
4. **质量层**：通过质量门禁 Skill 做全面审计
5. **守护层**：通过回归守护和 Mutation Testing 持续保障

核心理念：**AI 辅助 TDD 的最大价值不在于让 AI 写测试更快，而在于让人类从"写测试的人"升级为"设计测试策略的人"**。你负责思考"测什么"，Claude Code 负责"怎么测"。

---

## 参考来源

1. [Extend Claude with skills — Claude Code Official Docs](https://code.claude.com/docs/en/skills) — Anthropic 官方 Skills 文档，涵盖自定义命令和 Skill 创建
2. [Best practices for Claude Code — Claude Code Official Docs](https://code.claude.com/docs/en/best-practices) — 官方最佳实践，包含上下文管理和工作流建议
3. [TDD with Claude — Claude Code Ultimate Guide](https://github.com/FlorianBruniaux/claude-code-ultimate-guide/blob/main/guide/workflows/tdd-with-claude.md) — 社区验证的 Claude Code TDD 工作流
4. [Claude Code Skills Tutorial: Custom Slash Commands and Automations](https://supalaunch.com/blog/claude-code-skills-tutorial-custom-slash-commands-and-automations-guide) — 完整的 Slash Commands 创建教程
5. [Git Hooks with Claude Code: Quality Gates with Husky](https://dev.to/myougatheaxo/git-hooks-with-claude-code-build-quality-gates-with-husky-and-pre-commit-27l0) — Hooks 驱动的质量门禁实战

---

**训练营适用性评估**：

| 训练营类型 | 适用性 | 预计时长 | 备注 |
|-----------|--------|---------|------|
| AI 辅助开发中级营 | ⭐⭐⭐⭐⭐ | 4 小时 | 完美匹配，需前置 Claude Code 基础 |
| 企业工程效能训练营 | ⭐⭐⭐⭐ | 3 小时 | 侧重 Hooks 和质量门禁部分 |
| 全栈开发实战营 | ⭐⭐⭐ | 6 小时 | 需结合具体项目框架扩展 |
| TDD 专项训练营 | ⭐⭐⭐⭐ | 5 小时 | AI 辅助视角的 TDD 教学创新 |
| 团队规范化工作坊 | ⭐⭐⭐⭐ | 3 小时 | 侧重团队命令库和规则体系 |

> [!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学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
