tdd core principles

TDD 核心原则 · 垂直切片工作流

来源:Kent Beck "Test Driven Development by Example" + Martin Fowler "Refactoring" 提炼时间:2026-04-24


TDD 不是什么

TDD 不是"先写测试再写代码"。这个理解太浅,会导致实践变形。

TDD 是一种设计工作流——用测试来驱动接口设计,用快速反馈来驱动代码演进。


核心原则

1. 测试描述行为,不描述实现

好的测试:

// ✅ 描述行为
test('用户可以用书名搜索绘本', async () => {
  const results = await searchBooks('丢失的星星');
  expect(results).toContainEqual(expect.objectContaining({ title: '丢失的星星' }));
});

坏的测试:

// ❌ 描述实现
test('searchBooks 调用了 Prisma 的 where 参数', () => {
  const mock = prismaMock.book.findMany.mockResolvedTo([]);
  await searchBooks('test');
  expect(prismaMock.book.findMany).toHaveBeenCalledWith({
    where: expect.objectContaining({ title: { contains: 'test' } })
  });
});

为什么重要:实现可以随时改,测试不应该因为内部重构而失败。测试描述"能做什么",不是"怎么做"。

2. 垂直切片,不是横向切片

❌ 横向切片(错误方式):
  RED:   写 test1, test2, test3, test4, test5
  GREEN: 一次性写 impl1, impl2, impl3, impl4, impl5

✅ 垂直切片(正确方式):
  RED→GREEN: test1 → impl1
  RED→GREEN: test2 → impl2
  RED→GREEN: test3 → impl3

横向切片的问题: - 一次写所有测试,测试的是"想象的行为"而不是"实际的需求" - 测的是数据结构形状,不是用户价值 - 需求变时,测试全部要改

垂直切片的价值: - 每个测试都基于上一个测试学会的信息 - 每个测试都是对"这条 user story 是否完成"的验证 - 需求变时,只改相关的测试

3. 红 → 绿 → 重构,循环不颠倒

[RED]    写一个不通过的测试 → 确认哪里不对
[GREEN]  用最小代码让它通过     → 不求完美,只求通过
[REFACTOR] 在测试保护下改善代码  → 安全地改结构

关键规则: - 不跳过任何阶段 - RED 阶段不写任何实现代码 - GREEN 阶段不追求完美,只求测试通过 - REFACTOR 阶段在测试保护下大胆重构 - 永远不让系统处于 RED 状态过夜


行为测试的识别标准

满足以下任一条件的测试是行为测试:


与 AI coding 的关系

为什么 TDD 在 AI 时代更重要

AI 生成代码的问题:看起来对,实际可能不对。传统编程里,看一眼知道对不对;AI 生成时,每行看起来都对,要跑才知道。

TDD 提供了快速验证回路——AI 生成代码 → 测试立刻告诉你哪里不对 → AI 修正 → 再测。

没有测试,AI 代码的错误可能藏了很久才发现。

具体实践建议

用 AI 辅助 TDD: 1. 让 AI 先写测试(描述你想验证的行为) 2. 你 review 测试是否合理 3. 让 AI 基于测试写实现 4. 测试通过后,让 AI 提出重构机会

关键:不要让 AI 同时写测试和实现——这样 AI 会走捷径(测试mock一切让实现轻松通过)。


快速检验清单

拿到一个测试,问自己:


参考:Kent Beck "Test Driven Development by Example", 2002 参考:Martin Fowler "Refactoring", 2018