何时 Mock

仅在 system boundaries mock:

  • 外部 API(payment、email 等)
  • 数据库(有时——优先 test DB)
  • 时间/随机性
  • 文件系统(有时)

不要 mock:

  • 你自己的 class/module
  • Internal collaborator
  • 任何你控制的东西

为可 mock 性而设计

在 system boundaries,设计易 mock 的 interface:

1. 使用 dependency injection

将 external dependency 传入,而非内部创建:

// Easy to mock
function processPayment(order, paymentClient) {
  return paymentClient.charge(order.total);
}

// Hard to mock
function processPayment(order) {
  const client = new StripeClient(process.env.STRIPE_KEY);
  return client.charge(order.total);
}

2. 优先 SDK 风格 interface,而非 generic fetcher

为每个外部操作创建具体函数,而非一个带条件逻辑的 generic 函数:

// GOOD: Each function is independently mockable
const api = {
  getUser: (id) => fetch(`/users/${id}`),
  getOrders: (userId) => fetch(`/users/${userId}/orders`),
  createOrder: (data) => fetch('/orders', { method: 'POST', body: data }),
};

// BAD: Mocking requires conditional logic inside the mock
const api = {
  fetch: (endpoint, options) => fetch(endpoint, options),
};

SDK 方式意味着:
- 每个 mock 返回一种具体 shape
- test setup 中无条件逻辑
- 更易看出 test exercise 哪些 endpoint
- 每个 endpoint 有 type safety