实战

Claude Code 测试驱动开发(TDD)实战:AI 辅助红绿重构循环完全指南

Claude Code 与测试驱动开发(TDD)深度结合实战:让 Claude 先写测试再写实现的完整工作流、Red-Green-Refactor 循环的 AI 辅助方式、测试用例描述转换为 Jest/pytest/Go test 测试代码、边界条件和异常路径的自动发现、用 Claude 做变异测试(Mutation Testing)发现测试盲区、提升测试质量的提示词技巧,以及 TDD 在遗留代码改造中的应用方法。

2026/3/205分钟 阅读ClaudeEagle

TDD 的核心是「先写测试,再写实现」,Claude Code 能极大加速这个循环: 让 AI 帮你想到所有边界条件,让测试先于代码存在。

TDD 工作流:3 步循环

Red → 写失败的测试(描述期望行为) ↓ Green → 写最简单的实现让测试通过 ↓ Refactor → 重构代码,测试依然绿色 ↓ (循环)

Claude Code 加速每一步:

  • Red:告诉 Claude 需求,让它生成全面的测试用例
  • Green:让 Claude 写最简实现(刻意不过度设计)
  • Refactor:让 Claude 找出可以改进的地方

第一步:从需求描述生成测试

你:我要实现一个密码强度验证函数 validatePassword(password: string), 规则: - 长度 8-128 位 - 必须包含大写字母 - 必须包含小写字母 - 必须包含数字 - 可选:包含特殊字符(!@#$%^&*)会提升强度评级 - 返回 {valid: boolean, strength: 'weak'|'medium'|'strong', errors: string[]} 先不要写实现,只写完整的 Jest 测试用例, 要覆盖正常情况、所有边界条件、组合情况 Claude: import { validatePassword } from "./password"; describe("validatePassword", () => { // 有效密码 describe("valid passwords", () => { test("基础有效密码(8位,含大小写+数字)", () => { const result = validatePassword("Abc12345"); expect(result.valid).toBe(true); expect(result.errors).toHaveLength(0); }); test("包含特殊字符 → strength=strong", () => { const result = validatePassword("Abc123!@"); expect(result.valid).toBe(true); expect(result.strength).toBe("strong"); }); }); // 长度边界 describe("length validation", () => { test("7位密码 → 无效", () => { const result = validatePassword("Abc1234"); expect(result.valid).toBe(false); expect(result.errors).toContain("密码长度至少 8 位"); }); test("8位密码 → 有效(边界)", () => { expect(validatePassword("Abcd1234").valid).toBe(true); }); test("128位密码 → 有效(边界)", () => { const pwd = "Aa1" + "x".repeat(125); expect(validatePassword(pwd).valid).toBe(true); }); test("129位密码 → 无效", () => { const pwd = "Aa1" + "x".repeat(126); expect(validatePassword(pwd).valid).toBe(false); }); }); // 字符类型 describe("character requirements", () => { test("全小写 → 缺大写错误", () => { const result = validatePassword("abcdef12"); expect(result.errors).toContain("必须包含大写字母"); }); test("全大写 → 缺小写错误", () => { const result = validatePassword("ABCDEF12"); expect(result.errors).toContain("必须包含小写字母"); }); test("无数字 → 缺数字错误", () => { const result = validatePassword("Abcdefgh"); expect(result.errors).toContain("必须包含数字"); }); test("同时缺大写+数字 → 返回两个错误", () => { const result = validatePassword("abcdefgh"); expect(result.errors).toHaveLength(2); }); }); // strength 评级 describe("strength rating", () => { test("仅满足最低要求 → weak", () => { expect(validatePassword("Abcdef12").strength).toBe("weak"); }); test("较长密码(16位以上)→ medium", () => { expect(validatePassword("Abcdefghijk12345").strength).toBe("medium"); }); test("含特殊字符 → strong", () => { expect(validatePassword("Abc12!@#").strength).toBe("strong"); }); }); // 边缘情况 describe("edge cases", () => { test("空字符串 → 无效", () => { expect(validatePassword("").valid).toBe(false); }); test("只有空格 → 无效", () => { expect(validatePassword(" ").valid).toBe(false); }); }); });

第二步:让 Claude 写最简实现

你:测试已经写好了,现在帮我写 validatePassword 的最简实现, 让所有测试通过。不要过度设计,先让测试绿了再说。 Claude: export function validatePassword(password: string) { const errors: string[] = []; if (password.length < 8) errors.push("密码长度至少 8 位"); if (password.length > 128) errors.push("密码长度不能超过 128 位"); if (!/[A-Z]/.test(password)) errors.push("必须包含大写字母"); if (!/[a-z]/.test(password)) errors.push("必须包含小写字母"); if (!/[0-9]/.test(password)) errors.push("必须包含数字"); if (/^\s+$/.test(password)) errors.push("密码不能全为空格"); const valid = errors.length === 0; const hasSpecial = /[!@#$%^&*]/.test(password); const isLong = password.length >= 16; let strength: "weak" | "medium" | "strong" = "weak"; if (valid) { if (hasSpecial) strength = "strong"; else if (isLong) strength = "medium"; } return { valid, strength, errors }; }
bash
# 运行测试验证
npx jest password.test.ts --verbose
# All tests passed ✓

第三步:让 Claude 找重构机会

你:测试已经全部通过了,帮我重构 validatePassword: 找出可以改进的地方(可读性/可维护性/可扩展性), 重构后确保测试仍然全部通过 Claude:建议重构为策略模式(便于扩展新规则): const RULES = [ { test: (p: string) => p.length >= 8, error: "密码长度至少 8 位", }, { test: (p: string) => p.length <= 128, error: "密码长度不能超过 128 位", }, // ... 其余规则 ];

发现测试盲区:变异测试辅助

你:帮我对 validatePassword 做变异测试分析: 假设我把代码中的以下地方改错了,现有测试能否捕获? 1. 把 < 8 改为 <= 8(长度边界) 2. 把 [A-Z] 改为 [a-Z](大写检测) 3. 把 length === 0 的判断去掉 Claude: 变异 1(< 8 改为 <= 8): - 能被捕获:测试「8位密码→有效」会变成失败 ✓ 变异 2([A-Z] 改为 [a-Z]): - 能被捕获:测试「全小写→缺大写错误」会失败 ✓ 变异 3(去掉空字符串判断): - 部分能捕获,但你的空字符串测试覆盖不够完整 ⚠️ 建议补充测试:空字符串应该报「密码长度至少 8 位」而不是「全为空格」

遗留代码 TDD 改造

你:这个老函数没有任何测试,我需要重构它但不能破坏现有行为。 第一步:帮我写「特征测试」(Characterization Tests), 描述这个函数现在的实际行为(不管对不对), 让我安全地重构 [粘贴遗留函数] Claude:根据代码分析,该函数的当前行为是: [生成特征测试,记录现有行为,包括可能的 Bug 行为] 注意:test case #3 发现了一个 Bug: 当输入为负数时返回 0 而不是抛出错误,这可能是预期行为也可能是 Bug, 你需要和业务方确认。

来源:Claude Code 官方文档 - docs.anthropic.com/en/docs/claude-code

相关文章推荐

实战用 AI 写单元测试:Claude Code 自动化测试生成完全指南Claude Code AI 自动化测试生成完全指南:为什么 AI 特别适合写测试、Jest/pytest/JUnit 三大框架使用示例、四大高价值测试场景(提升覆盖率/TDD/回归测试/批量补测试)、高质量测试 Prompt 写法、CLAUDE.md 固化测试规范与常见问题解答。2026/3/14实战Claude Code 测试覆盖率提升实战:从 30% 到 80% 的系统化方法用 Claude Code 系统性提升测试覆盖率的完整方法:快速识别覆盖率盲区(Istanbul/Coverage.py 报告解读)、让 Claude 针对未覆盖行生成测试的精准提示词、边界条件和异常路径的自动发现、集成测试 vs 单元测试的覆盖率策略、Mock 复杂依赖(数据库/HTTP/时间)的方法、测试质量 vs 测试数量的平衡、以及在 CI 中设置覆盖率门禁阻止质量退化。2026/3/21实战Claude Code 自动生成测试用例:单元测试、集成测试和 E2E 测试完整指南Claude Code 自动生成测试用例完整指南:从函数签名生成边界条件测试、Table-Driven 测试模式、Mock 依赖注入、集成测试数据库 Fixtures、Playwright E2E 测试生成,以及提升测试覆盖率的系统化 Prompt 策略和 TDD 工作流。2026/3/16实战实战者说:Harper Reed 分享 Claude Code 真实工作流——TDD、预提交钩子与 prompt_planHarper Reed(奥巴马 2012 竞选技术总监)分享 Claude Code 真实工作流:GPT-4o 打磨想法→推理模型生成 spec.md→生成 prompt_plan.md→Claude 自动执行计划,配合 TDD、Linting 和 Pre-commit Hooks 三大防御性实践,实现 30-45 分钟完成完整开发计划。2026/3/2实战Harper Reed 的 Claude Code 实战工作流:Spec 驱动开发 + TDD + 提交计划的黄金组合Harper Reed 分享的 Claude Code Spec 驱动开发工作流:用推理模型(o1/o3)生成规格说明和提示计划,Claude Code 按计划逐步执行并自动追踪进度。配合 TDD、Linting、Pre-commit Hooks 三大防御性编码实践,团队在 30-45 分钟内完成新功能开发。2026/2/28实战Claude Code 命令行工具开发实战:用 AI 快速构建专业 CLI 工具Claude Code 辅助命令行工具(CLI)开发的完整实战指南:Python Click/Typer、Go Cobra、Rust Clap 技术栈选型、用 Claude Code 生成完整 CLI 项目结构(参数解析/子命令/全局选项)、交互式提示和彩色输出、配置文件管理、Shell 自动补全生成、跨平台打包(PyInstaller/goreleaser),以及发布到 PyPI/npm/Homebrew 的完整流程。2026/3/26