好测试与差测试

好测试

Integration-style: 通过真实 interface 测试,非 mock 内部部件。

// GOOD: Tests observable behavior
test("user can checkout with valid cart", async () => {
  const cart = createCart();
  cart.add(product);
  const result = await checkout(cart, paymentMethod);
  expect(result.status).toBe("confirmed");
});

特征:

  • 测试用户/caller 关心的 behavior
  • 仅使用 public API
  • 能在 internal refactor 后存活
  • 描述 WHAT,非 HOW
  • 每个 test 一个 logical assertion

差测试

Implementation-detail tests:与 internal structure 耦合。

// BAD: Tests implementation details
test("checkout calls paymentService.process", async () => {
  const mockPayment = jest.mock(paymentService);
  await checkout(cart, payment);
  expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
});

危险信号:

  • Mock internal collaborator
  • 测试 private method
  • 断言 call count/order
  • refactor 未改 behavior 时 test 仍 break
  • test 名描述 HOW 而非 WHAT
  • 绕过 interface 验证
// BAD: Bypasses interface to verify
test("createUser saves to database", async () => {
  await createUser({ name: "Alice" });
  const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
  expect(row).toBeDefined();
});

// GOOD: Verifies through interface
test("createUser makes user retrievable", async () => {
  const user = await createUser({ name: "Alice" });
  const retrieved = await getUser(user.id);
  expect(retrieved.name).toBe("Alice");
});