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