← 中文资源

简体中文版本

在 mock、stub 与 fake 之间做刻意选型

按测试要回答的问题选替身:stub 管状态准备、mock 验证交互、fake 提供真实行为,避免一刀切。

阅读英文原文

目标

stub 回答“有哪些输入”,fake 回答“依赖如何表现”,mock 回答“约定的交互是否发生”。误用源于先选替身后想问题:全 mock 长出脆弱的调用序列测试,只做 stub 则长出无法有意义失败的测试。先定问题,选型就变成机械操作。

步骤要点

  1. 按交互断言密度给文件排名,定位 mock 滥用集中区。
  2. 把交互检查改成状态断言:不再断言 send 被怎么调,而是断言发件箱里有收件人正确的邮件。
  3. 行为重要的依赖用 fake:FakeClock 显式 advance,确定性且瞬时。
  4. 交互本身就是契约处保留 mock:checkout 恰好 charge 一次,断言即规格。
  5. 把选型规则写进文档,评审有了共享语言,新测试继承词汇表。

排错提示

无害重构导致一片红,说明测试耦合了管道,逐个改成走公共 API 的状态断言;fake 与真实行为漂移就加契约测试套件,同一组断言对真实现与 fake 都跑,分歧即失败;mock 搭建淹没测试本体,说明被测单元协作者太多,先抽出接缝再测更小的单元。

适用边界

fake 需要维护以跟随真实行为,契约测试只能限制漂移不能消灭成本;交互确属契约时交互测试是正当的,全盘弃 mock 与只用 mock 同样教条。

代码示例

// Interaction is the spec: mock is right
expect(gateway.charge).toHaveBeenCalledTimes(1);

// Outcome is the spec: state assertion is right
const outbox = await emails.forUser(user.id);
expect(outbox[0].to).toBe(user.email);