测试驱动开发 (TDD) 与 Claude Code 的协作实践详解
1. 传统 TDD 的核心逻辑
TDD 的流程可归纳为 红-绿-重构(Red-Green-Refactor):
红 (Red): 为尚未实现的功能写测试 → 测试失败,明确目标。
绿 (Green): 编写最小化代码 → 让测试通过。
重构 (Refactor): 在测试保护下优化代码结构。
关键点:测试由“事后检查”转变为“开发驱动力”。
2. Claude Code 如何实践 TDD?
Claude Code 的实践流程与传统 TDD 完全一致:
第一步:编写测试(红阶段)
你可以清晰地描述功能需求,让 Claude 先生成测试。比如:
你好,Claude。我正在为一个电商网站开发购物车功能。请使用 Jest 和 React Testing Library,为即将开发的 useShoppingCart hook 编写测试文件 useShoppingCart.test.js。测试必须覆盖以下场景:
1. 当购物车为空时,调用 addItem 添加一个新商品,购物车内应包含该商品,数量为 1。
2. 当一个商品已存在于购物车时,再次调用 addItem 添加同一个商品,该商品的数量应该增加 1,而不是新增一条记录。
3. 调用 removeItem 可以将商品从购物车中完全移除。
4. 调用 updateQuantity 可以将商品的数量更新为指定值。
5. 如果尝试将商品数量更新为 0 或负数,应将其从购物车中移除。
第二步:生成功能代码(绿阶段)
当 Claude 输出测试文件后,你可以继续指令:
很好,测试文件 useShoppingCart.test.js 看起来很完整。现在,请创建并编写 useShoppingCart.js 文件,实现 useShoppingCart hook 的所有逻辑,确保刚才生成的所有测试用例都能成功通过。
Claude 会根据测试目标,逐步补齐代码逻辑,直到所有测试通过。
第三步:重构代码(重构阶段)
在测试通过后,可以要求 Claude 对代码进行重构,优化命名、结构和可读性。由于有测试用例保护,重构风险大大降低。
3. 示例代码
useShoppingCart.test.js
import { renderHook, act } from '@testing-library/react';
import useShoppingCart from './useShoppingCart';describe('useShoppingCart', () => {test('adds a new item to an empty cart with quantity 1', () => {const { result } = renderHook(() => useShoppingCart());act(() => result.current.addItem({ id: 1, name: 'Apple' }));expect(result.current.items).toEqual([{ id: 1, name: 'Apple', quantity: 1 }]);});test('increments quantity when adding same item again', () => {const { result } = renderHook(() => useShoppingCart());act(() => result.current.addItem({ id: 1, name: 'Apple' }));act(() => result.current.addItem({ id: 1, name: 'Apple' }));expect(result.current.items[0].quantity).toBe(2);});test('removes item from cart', () => {const { result } = renderHook(() => useShoppingCart());act(() => result.current.addItem({ id: 1, name: 'Apple' }));act(() => result.current.removeItem(1));expect(result.current.items).toEqual([]);});test('updates item quantity', () => {const { result } = renderHook(() => useShoppingCart());act(() => result.current.addItem({ id: 1, name: 'Apple' }));act(() => result.current.updateQuantity(1, 5));expect(result.current.items[0].quantity).toBe(5);});test('removes item if quantity set to 0 or negative', () => {const { result } = renderHook(() => useShoppingCart());act(() => result.current.addItem({ id: 1, name: 'Apple' }));act(() => result.current.updateQuantity(1, 0));expect(result.current.items).toEqual([]);});
});
useShoppingCart.js
import { useState } from 'react';export default function useShoppingCart() {const [items, setItems] = useState([]);const addItem = (item) => {setItems((prev) => {const existing = prev.find((i) => i.id === item.id);if (existing) {return prev.map((i) =>i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i);}return [...prev, { ...item, quantity: 1 }];});};const removeItem = (id) => {setItems((prev) => prev.filter((i) => i.id !== id));};const updateQuantity = (id, qty) => {if (qty <= 0) {removeItem(id);return;}setItems((prev) =>prev.map((i) => (i.id === id ? { ...i, quantity: qty } : i)));};return { items, addItem, removeItem, updateQuantity };
}
测试运行截图(Jest)
PASS ./useShoppingCart.test.jsuseShoppingCart✓ adds a new item to an empty cart with quantity 1 (15 ms)✓ increments quantity when adding same item again (3 ms)✓ removes item from cart (2 ms)✓ updates item quantity (2 ms)✓ removes item if quantity set to 0 or negative (2 ms)
4. 为什么这种方法对 AI 特别有效?
目标清晰:测试定义了精确的输出边界,避免模糊描述。
结构化思考:AI 需要逐步推演才能通过测试,避免“一次性胡乱生成”。
高层验证:结果是否正确由测试验证,而不是仅凭直觉判断。
自由与约束结合:AI 有自由生成实现方式,但最终必须满足约束条件。
这实际上是一种 高级 Prompt Engineering 技巧:用测试来替代模糊的提示,直接给 AI 一个靶子。
5. 不止 Claude Code,其他 AI 编程工具也适用
需要强调的是,这种 TDD + AI 协作的工作流 不仅限于 Claude Code:
Cursor:基于 VSCode 的 AI IDE,能和测试框架无缝集成。
Gemini-cli:命令行驱动的 AI 编程助手,也能快速生成测试与实现。
ChatGPT / Copilot:同样可以通过类似的 TDD 约束方式,提升输出稳定性与可控性。
无论是哪种 AI 工具,TDD 都是让 AI 编程更可靠、更可控的核心方法论。
总结与实战建议
在开始编码前,先写测试,再写实现。
将 AI 当作配合测试的实现者,而不是“灵感随手助手”。
结合 Cursor、Claude、Gemini-cli 等工具,可以打造出生产级 AI 编程工作流。
这就是 TDD + AI 协作 的真正威力:让 AI 不再是“黑盒子”,而是一个能持续交付、可控的开发伙伴。