测试

测试驱动开发(TDD)入门与实践心得

测试驱动开发(Test-Driven Development)是一种「测试先行」的软件开发方法。它要求你在编写功能代码之前,先编写一个会失败的测试。听起来反直觉,但实践者都说:TDD 改变了他们写代码的方式。

红-绿-重构循环

TDD 的核心是一个三步循环:

  1. 🔴 红:编写一个失败的测试,定义你期望的行为
  2. 🟢 绿:编写最少量的代码让测试通过
  3. 🔵 重构:在测试保护下改善代码结构

然后重复这个循环,每次只关注一个小功能点。

一个完整的 TDD 示例

假设我们要实现一个购物车总价计算功能:

第一步:写测试(红)

describe('ShoppingCart', () => {
  it('should calculate total price of items', () => {
    const cart = new ShoppingCart();
    cart.addItem({ name: 'Book', price: 29.99 });
    cart.addItem({ name: 'Pen', price: 3.50 });
    expect(cart.getTotal()).toBe(33.49);
  });
});

第二步:最简实现(绿)

class ShoppingCart {
  constructor() {
    this.items = [];
  }

  addItem(item) {
    this.items.push(item);
  }

  getTotal() {
    return this.items.reduce((sum, item) => sum + item.price, 0);
  }
}

第三步:添加新测试,扩展功能

it('should apply discount when total exceeds 100', () => {
  const cart = new ShoppingCart();
  cart.addItem({ name: 'Laptop', price: 120 });
  expect(cart.getTotal()).toBe(108); // 10% off
});

TDD 的实际收益

  • 更好的设计:先写测试迫使你从使用者角度思考 API
  • 即时反馈:每次改动都有测试验证,信心十足
  • 活文档:测试用例展示了代码的预期行为
  • 更少的 Bug:边界条件在写测试时就被考虑到
  • 重构安全网:有测试覆盖,重构不再可怕

常见误解

  • 「TDD 会降低开发速度」:短期看似慢,长期因减少调试和返工而更快
  • 「要 100% 测试覆盖率」:关注关键路径和业务逻辑,不必追求数字
  • 「TDD 只适用于单元测试」:TDD 可以应用于任何级别的测试
「TDD 的价值不在于测试本身,而在于它驱动你写出可测试的、设计良好的代码。」

如何开始

  1. 选择一个小的、独立的功能模块练手
  2. 从最简单的 happy path 测试开始
  3. 逐步添加边界条件和异常场景
  4. 坚持至少两周,让红-绿-重构成为肌肉记忆
  5. 在 Code Review 中分享你的 TDD 实践