一、TDD基础:什么是测试驱动开发

说实话,我第一次接触TDD时,心里是抗拒的。

“先写测试再写代码?这不是反人类吗?”我当时就是这么想的。

但后来在一个React项目中,我被bug追着跑了三个月。每次改一个功能,就冒出两个新bug。那时候我才意识到——嗯,也许TDD真有点东西。

1.1 什么是测试驱动开发

测试驱动开发,英文叫Test-Driven Development,简称TDD。

说白了,就是先写测试,再写代码。不是写完代码再补测试,而是反过来。

你想想看,这就像盖房子之前先画图纸。没有图纸就开工,最后大概率要返工。

TDD的核心思想:用测试来驱动代码的设计和实现,而不是用代码来驱动测试的编写。

我在项目中遇到过很多团队,他们所谓的“测试”就是上线前手动点一遍。结果呢?每次发布都像在赌博。

1.2 TDD的红-绿-重构循环

TDD有三个步骤,我习惯叫它“红-绿-重构”循环。听起来像交通信号灯?没错,就是这个意思。

  1. 红灯阶段(Red):先写一个会失败的测试
  2. 绿灯阶段(Green):写最少的代码让测试通过
  3. 重构阶段(Refactor):优化代码,保持测试通过

这三个步骤不断重复,就像呼吸一样自然。

我的小技巧:在红灯阶段,我通常会先想清楚“这个功能到底要做什么”。测试写清楚了,代码怎么写就清晰了。

举个例子,假设我们要写一个加法函数:

// 红灯阶段:先写测试
test('add(1, 2) 应该返回 3', () => {
  expect(add(1, 2)).toBe(3);
});

// 绿灯阶段:写最简代码
function add(a, b) {
  return a + b;
}

// 重构阶段:优化(这里已经很简单了,不需要重构)

你可能会说:“这也太简单了吧?”没错,TDD就是从这种小步快跑开始的。

1.3 为什么要在React中使用TDD

这个问题我问过自己很多次。尤其是在React项目中,组件交互复杂,状态管理混乱,测试真的有必要吗?

我的答案是:越复杂,越需要TDD

场景 没有TDD 有TDD
修改一个组件 担心影响其他组件 测试会告诉你哪里出问题
新增功能 手动测试所有相关页面 跑一遍测试就知道
重构代码 不敢动,怕改出bug 放心重构,测试兜底
团队协作 每个人改自己的,互不信任 测试就是契约,大家都放心

我曾经在一个React项目中,接手了一个没有测试的代码库。改一个按钮样式,结果把整个表单提交逻辑搞崩了。你猜怎么着?上线后用户投诉,我们花了三天才定位到问题。

避坑指南:我曾经以为“小项目不需要测试”,结果小项目变成了大项目,测试成本翻了十倍。记住:测试不是成本,是投资。

1.4 React中TDD的独特优势

React的组件化特性,让TDD变得特别顺手。

  • 组件即函数:给定props,返回UI。测试起来非常直接
  • 状态管理可预测:用React Testing Library模拟用户操作,验证状态变化
  • Hooks可单独测试:自定义hooks可以脱离组件单独测试

举个例子,测试一个简单的计数器组件:

// 红灯:先写测试
test('点击按钮后计数增加', () => {
  render(<Counter />);
  const button = screen.getByText('+1');
  fireEvent.click(button);
  expect(screen.getByText('计数: 1')).toBeInTheDocument();
});

// 绿灯:实现组件
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>+1</button>
    </div>
  );
}

你看,测试写完了,组件怎么设计也就清楚了。这就是TDD的魅力——测试驱动设计

1.5 什么时候不适合用TDD

说实话,TDD不是万能的。我也不会在所有场景都用它。

  • 原型开发:快速验证想法时,先写代码再补测试
  • 探索性编程:不确定怎么实现时,先写代码试试
  • UI动画:视觉效果的测试比较难写,可以适当放宽

但记住:生产代码一定要有测试。这是底线。

我的建议:刚开始学TDD时,不要追求100%覆盖率。从核心逻辑开始,慢慢养成习惯。我花了大概两个月才真正适应这种开发方式。

好了,这一章我们聊了TDD的基础概念。下一章,我们会深入React Testing Library,看看怎么在React项目中真正落地TDD。

记住:先写测试,再写代码。这不是浪费时间,是在为你未来的自己铺路。