# Lesson 22.4: TDD Prompt 模板——从需求到代码的结构化桥梁

## 本课目标

- 掌握三阶段 Prompt 模板体系：测试场景 → 测试细节 → 测试与实现
- 理解"人工 Review 卡点"在 AI 辅助 TDD 中的关键作用
- 学会用结构化 Prompt 把抽象需求转化为可验证的测试用例
- 能够在实际项目中运用这套模板驱动 Claude 生成高质量代码

> **前置知识**：本课建立在 Lesson 22（TDD 基础）和 Lesson 14（PRD 创建）的基础上。

## 核心内容

### 为什么需要 Prompt 模板？

Lesson 22 教了你 `/tdd` 的 RED→GREEN→REFACTOR 循环。但在实际操作中，你可能会遇到这样的困境：

```
你："帮我实现一个用户反馈功能"
Claude：（直接开始写代码，跳过了对需求的深入理解）
你："等等，我还没想清楚要测什么……"
```

**问题不在于 Claude 不会写代码，而在于你没有把"什么算对"说清楚。**

TDD Prompt 模板解决的就是这个问题——它提供了一条从模糊需求到精确测试的结构化路径：

```
需求（模糊的）
  ↓ 测试场景 Prompt → 测试场景（自然语言，易审查）
  ↓ 测试细节 Prompt → 测试细节（SUT、方法、参数、断言）
  ↓ 测试与实现 Prompt → 测试代码 + 功能实现
```

### 三阶段 Prompt 模板

#### 阶段一：需求 → 测试场景

**作用**：把功能需求转化为可测试的场景列表。

**Prompt 模板**：

```markdown
功能需求
====
{粘贴你的需求描述}

任务
====
请根据上面的功能需求，列出需要测试的场景。描述场景，并给出相关的测试数据。保持简洁。

样例
===
需求为 ArgParser。
输出：

1. 布尔标志测试
   - 场景描述：测试解析程序是否可以正确处理布尔标志
   - 测试数据：`-l -p 8080`
   - 预期结果：`{"l": true}`
```

> 模板中的样例作为 few-shot example，让 LLM 的输出格式更稳定。

**产出示例**——假设需求是"实现一个优惠券系统"：

```
1. 有效优惠券使用
   - 场景描述：用户使用未过期、未达上限的优惠券下单
   - 测试数据：优惠券 SAVE20，有效期 2026-12-31，每人限用 1 次，用户未使用过
   - 预期结果：订单金额打 8 折

2. 过期优惠券
   - 场景描述：用户使用已过期的优惠券
   - 测试数据：优惠券 EXPIRED，有效期 2025-01-01
   - 预期结果：拒绝使用，提示"优惠券已过期"

3. 超出使用次数
   - 场景描述：用户尝试第二次使用同一人限用 1 次的优惠券
   - 测试数据：用户已使用过 SAVE20，再次下单时输入 SAVE20
   - 预期结果：拒绝使用，提示"已达使用上限"
```

#### 阶段二：测试场景 → 测试细节

**作用**：在测试场景的基础上，确定被测对象、核心方法、入参和验证方式。

**Prompt 模板**：

```markdown
功能需求
====
{粘贴需求}

测试场景
===
{粘贴阶段一产出的测试场景}

任务
====
请根据需求和测试场景补充下面的测试细节：

- 被测试的类叫 {SUT Class name}。它的构造函数接受 {which dependency}；
- {SUT Class name} 的 {core method name} 方法返回 {return} 作为结果，接受 {parameter} 作为参数；
- 验证时，通过 {validation method}，完成验证

样例
===
需求为 实现一个命令行解析的工具。
输出：

- 被测试的类叫 ArgumentParser。它的构造函数接受 Map 作为参数配置；
- ArgumentParser 的 parse 方法返回 Map 作为解析结果，接受 args ("-l -p 8080") 作为参数；
- 验证时，通过从 Map 中获取对应参数值，完成验证
```

**产出示例**——接续优惠券系统：

```
- 被测试的类叫 CouponService。它的构造函数接受 CouponRepository 和 Clock 作为依赖；
- CouponService 的 apply 方法返回 OrderSummary（含折后金额）作为结果，
  接受 userId(Long) 和 couponCode(String) 作为参数；
- 验证时，通过检查 OrderSummary 的 discountAmount 和 finalAmount 字段完成验证
```

#### 阶段三：测试场景 + 测试细节 → 测试代码 + 实现

**作用**：在规范约束下，生成可运行的测试代码和功能实现。

**Prompt 模板**：

```markdown
功能需求
====
{粘贴需求}

测试场景
===
{粘贴测试场景}

任务
===
请根据 [功能需求] 和 [测试场景] 生成测试和代码实现。
测试细节：
{粘贴测试细节}

测试要求：
- 每个场景对应一个测试方法，方法内加中文注释标明测试场景
- 测试方法命名：should_xxx_when/if_condition 格式
- 使用 @Nested 分类各组测试
- 优先使用 state verification，少用 behavior verification
- 将时间、随机数等作为参数传入，保证测试稳定性
```

### 人工 Review 卡点：最关键的一步

在阶段一产出测试场景后、进入阶段二之前，**必须进行人工 Review**。

```
需求 → [Claude 生成] → 测试场景
                          ↓
                    🔍 人工 Review ← 不可跳过！
                          ↓
                    测试细节 → 测试与实现
```

**为什么要 Review 测试场景，而不是 Review 代码？**

> "以自然语言产生的测试/任务列表，我们更容易发现错误，并提出反馈。而以代码形式表示的功能代码，我们却很难在第一时间发现错误。因此我们就更需要在更早的时候提出反馈，避免错误的累积。"
> —— 徐昊《AI时代的软件工程》

**Review 检查清单**：

| 检查项 | 关注点 |
|--------|--------|
| 覆盖完整性 | 是否遗漏了重要的业务场景？ |
| 边界条件 | 空值、零值、最大值、并发等边界是否覆盖？ |
| 测试数据合理性 | 测试数据是否贴近真实业务？ |
| 预期结果明确性 | 每个场景的预期结果是否无歧义？ |
| 优先级 | 哪些场景是核心链路，必须通过？ |

**实际操作**：拿到 Claude 输出的测试场景后，花 2-3 分钟逐条检查。如果发现遗漏或错误，直接在自然语言层面修改——这比事后改代码成本低 10 倍。

### 完整流程示例

以"实现一个简单的待办事项 API"为例：

**Step 1：粘贴需求到阶段一 Prompt**

```
功能需求：实现一个 RESTful 待办事项 API，支持创建、查询、标记完成、删除操作。
每个待办事项有标题、描述、创建时间、完成状态。
```

**Step 2：Claude 输出测试场景（你 Review）**

```
1. 创建待办事项
   - 场景：POST /todos，传入标题和描述
   - 预期：返回 201，包含生成的 ID 和创建时间

2. 查询待办列表
   - 场景：GET /todos
   - 预期：返回所有待办事项列表

3. 标记完成
   - 场景：PATCH /todos/:id/complete
   - 预期：返回 200，completed 字段变为 true

4. 删除待办
   - 场景：DELETE /todos/:id
   - 预期：返回 204，再次查询该 ID 返回 404

5. 边界：创建空标题
   - 预期：返回 400，错误信息包含"标题不能为空"

6. 边界：操作不存在的 ID
   - 预期：返回 404
```

**你 Review 后补充**："还需要测试并发场景——两个请求同时标记同一个待办完成。"

**Step 3：将补充后的场景 + 阶段二 Prompt 交给 Claude**

Claude 输出测试细节：SUT 是 `TodoService`，依赖 `TodoRepository`，核心方法是 `create`/`findAll`/`complete`/`delete`……

**Step 4：将全部内容 + 阶段三 Prompt 交给 Claude**

Claude 生成测试代码和实现代码。

### 与 /tdd 和 /plan 的关系

这套模板不是替代 `/tdd` 或 `/plan`，而是**补充它们之间的缝隙**：

```
/plan          → 定义"做什么"（架构、任务分解）
    ↓
TDD Prompt 模板 → 把"做什么"精确化为"测什么"（测试场景、细节）
    ↓
/tdd           → RED → GREEN → REFACTOR（执行）
```

- `/plan` 产出的是任务列表和架构方案
- TDD Prompt 模板产出的是测试场景和验证标准
- `/tdd` 根据这些标准执行具体的编码循环

**当你觉得 `/tdd` 的输入不够清晰时**——比如需求很复杂、边界情况很多——先用这套模板梳理测试场景，再交给 `/tdd` 执行。

## 常见问题

**Q: 这套模板只能用于 Java 吗？**

A: 模板本身是语言无关的。三阶段的思路（场景→细节→实现）适用于任何语言。原文中的 Java 规范（JUnit5、Stream API 等）只是阶段三的一个示例规则集——你可以替换成 TypeScript + Jest、Python + pytest 等任何技术栈的规范。

**Q: 每次开发都要走三阶段吗？**

A: 不一定。简单功能（如"加一个配置项"）可以直接 `/tdd`。三阶段模板适合：
- 复杂业务逻辑（优惠券、支付、权限）
- 边界情况多的功能（输入验证、状态机）
- 你对需求还不够确定时（用阶段一帮你理清思路）

**Q: 人工 Review 真的不能跳过吗？**

A: 对于核心业务逻辑，不建议跳过。徐昊的观点是：自然语言阶段的纠错成本远低于代码阶段。如果你对需求非常确定、场景很简单，可以快速扫一遍就进入阶段二——但"扫一遍"这个动作本身不能省。

## 下一步

请调用 `AskUserQuestion` 展示以下选项，让学习者点击选择；从每条中提炼 1-5 个词作为 label，其余写入 description，不要要求输入数字：

- 实践：选择一个你正在开发的功能，用阶段一 Prompt 生成测试场景
- 深入：Lesson 22.1 - EDD 实战——用 Eval 量化 AI 的 TDD 表现
- 返回：Lesson 22 - 测试与代码审查

---
*阶段 4 | Lesson 22.4/26 | 上一课: Lesson 22.3 - 编码原则 | 下一课: Lesson 22.5 - 无人评测架构*
