Mock 概念与为什么需要 Mock 回放

说个实在的,不管你是做微服务还是单体应用,只要涉及外部依赖,就一定逃不过 Mock。

Mock 到底是啥?说白了,它就是帮你「伪造」一个服务。比如你的代码要调支付接口,总不能每次跑测试都真扣钱吧?Mock 就是那个替身,返回你想要的结果。

Mock 的基础概念:替身演员

我习惯把 Mock 理解成「测试界的替身演员」。正主(真实服务)太金贵或者太慢,就找个替身来搭戏。这个替身必须具备两个特点:

  • 返回值可控:你让它返回成功,它就返回成功;你让它抛异常,它就抛异常。
  • 零副作用:调用 Mock 不会真的扣钱、不会真的发邮件、不会真的写数据库。

举个例子:

// 真实支付服务
public interface PaymentService {
    boolean charge(String userId, double amount);
}

// Mock 版本 —— 你希望它总是返回 true
PaymentService mockService = Mockito.mock(PaymentService.class);
when(mockService.charge("test_user", 100.0)).thenReturn(true);

这段代码里,mockService 根本不会去调第三方支付网关,它只是乖乖返回 true。嗯,这就是 Mock 最朴素的功能。

为什么需要 Mock?三个核心痛点

我在项目中遇到过不少团队,刚开始觉得 Mock 能省事,结果越用越乱。我总结了三个必须用 Mock 的场景:

  1. 依赖不可用:测试环境里,数据库、缓存、消息队列经常不在线。Mock 帮你把它们「虚拟化」。
  2. 测试速度太慢:一个接口调远程服务要打几个来回,网络延迟加起来好几秒。Mock 直接把延迟砍到微秒级。
  3. 模拟异常场景:你真的指望生产环境给你来一次断网?Mock 可以轻松模拟超时、500 错误、空指针。

注意:Mock 不是越大越好。过度 Mock 会导致测试与真实行为脱节,后面你会看到 Mock 回放正是来解决这个问题的。

Mock 的局限性:为什么需要回放?

你想想看,传统的 Mock 有一个致命问题——它跟真实行为脱钩。什么意思呢?

比如你 Mock 了支付接口返回 true,但如果真实支付接口某天改了返回格式,你的 Mock 是不知道的。测试照样全绿,上线就炸。

我之前就吃过这个亏。有一次对接的第三方订单系统升级了接口,我这边 Mock 里的字段名没跟上。CI 跑得挺欢,一上线就报「字段不存在」。排查了半天,最后发现是 Mock 和真实接口对不上了。

这就引出了 Mock 回放的必要性。回放机制的核心思路是:

  • 录制:先对着真实服务跑一次,把请求和响应录下来。
  • 回放:下次跑测试时,直接拿录制的内容来 Mock,
  • 校验:如果真实服务变了,回放时会自动检测不匹配。

一句话总结:传统 Mock 是「猜」答案,Mock 回放是「抄」答案,而且每次 CI 都要保证你抄的答案还是对的。

Mock 在 CI 流程中的位置

我习惯用下面这个图来说明 Mock 回放在整个 CI 流水线中的角色。说真的,它卡在「单元测试」和「集成测试」之间,既保证了速度,又不失可靠性。

Mock 回放在 CI 流程中的位置 代码提交 录制阶段 调真实服务,存请求/响应 回放验证阶段 用录制内容 Mock,跑测试 结果校验 ✅ 通过 ❌ 失败(报警) 说明 录制一次,回放 N 次 回放时不需要真实依赖 失败说明 Mock 过期了 需要重新录制 传统 Mock 手动写死返回值 容易与真实接口脱节 CI 全绿但上线炸

什么时候用传统 Mock,什么时候用回放?

我习惯按稳定性来区分。话说回来,也不是所有场景都需要回放。下面这张表是我在实际项目中总结的经验:

场景 传统 Mock Mock 回放
第三方支付接口 ❌ 不可靠,易变 ✅ 推荐
内部基础服务(如鉴权) ✅ 相对稳定 可选
数据库查询 ✅ 常用 ❌ 性价比低
消息队列 ❌ 异步难模拟 ✅ 推荐
遗留系统(无人维护) ❌ 不靠谱 ✅ 必须用

我的习惯:对于「别人维护、我不改、但常出问题」的依赖,一律上 Mock 回放。对于「我自己维护、代码可见」的内部模块,用传统 Mock 就够了。

一点个人体会

曾经有一个项目,我们团队对每个外部依赖都写了传统 Mock,CI 跑得飞快,一次都没出过错。结果上线第一天,订单模块直接瘫痪。原因?Mock 返回的字段名和真实接口不一致,前端拿不到数据。

从那以后,我立了一个规矩:凡是外部依赖的测试,必须从真实录制开始。Mock 回放不是给自己找麻烦,而是给 CI 上了一道保险。

说白了,Mock 回放就是把「我以为它没问题」变成「它真的没问题」。

核心观点:Mock 是 CI 提速的手段,回放是 CI 保质的底线。两者结合,才能在快速迭代中不翻车。