Files
2026-07-13 21:35:35 +08:00

1.6 KiB

好的测试与糟糕的测试

好的测试

集成风格:通过真实接口进行测试,而非模拟内部组件。

// 好:测试可观察的行为
test("用户可以使用有效购物车完成结账", async () => {
  const cart = createCart();
  cart.add(product);
  const result = await checkout(cart, paymentMethod);
  expect(result.status).toBe("confirmed");
});

特征:

  • 测试用户/调用者关心的行为
  • 仅使用公开 API
  • 能够经受内部重构
  • 描述「做什么」,而非「怎么做」
  • 每个测试只有一个逻辑断言

糟糕的测试

实现细节测试:与内部结构耦合。

// 差:测试实现细节
test("结账时调用 paymentService.process", async () => {
  const mockPayment = jest.mock(paymentService);
  await checkout(cart, payment);
  expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
});

危险信号:

  • 模拟内部协作对象
  • 测试私有方法
  • 对调用次数/顺序进行断言
  • 重构(未改变行为)时测试破裂
  • 测试名称描述「怎么做」而非「做什么」
  • 通过外部手段而非接口进行验证
// 差:绕过接口进行验证
test("createUser 保存到数据库", async () => {
  await createUser({ name: "Alice" });
  const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
  expect(row).toBeDefined();
});

// 好:通过接口进行验证
test("createUser 使用户可被检索到", async () => {
  const user = await createUser({ name: "Alice" });
  const retrieved = await getUser(user.id);
  expect(retrieved.name).toBe("Alice");
});