1. 传统 TDD 的核心逻辑

TDD 的流程可归纳为 红-绿-重构(Red-Green-Refactor)

  1. 红 (Red): 为尚未实现的功能写测试 → 测试失败,明确目标。

  2. 绿 (Green): 编写最小化代码 → 让测试通过。

  3. 重构 (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.js
  useShoppingCart
    ✓ 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 特别有效?

  1. 目标清晰:测试定义了精确的输出边界,避免模糊描述。

  2. 结构化思考:AI 需要逐步推演才能通过测试,避免“一次性胡乱生成”。

  3. 高层验证:结果是否正确由测试验证,而不是仅凭直觉判断。

  4. 自由与约束结合: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 不再是“黑盒子”,而是一个能持续交付、可控的开发伙伴。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐