为什么需要 Mock 适配器?测试痛点与架构思考

做 Android 接口测试,迟早会遇到一个很尴尬的场面:明明代码写好了,跑测试却得等后端接口就绪。我早些年就踩过这个坑,项目组每天因为联调时间吵得不可开交。今天就聊聊,为什么我们需要 Mock 适配器来解这个局。

核心观点:
测试应该尽早、独立运行,不依赖任何外部服务。Mock 适配器就是帮我们在本地模拟网络响应,让测试变得可控、可重复。

你肯定碰到过的测试痛点

咱们先列举几个真实现状。你在写单元测试时,是不是经常遇到下面这些情况?

  • 接口没写好 —— 前端等后端接口,测试进度卡死。
  • 网络不稳定 —— 跑一次测试,可能因为超时或断网而失败。
  • 数据难造 —— 想测某个边界值,后端压根没提供这个数据。
  • 测试太慢 —— 每次都要走真实 HTTP 请求,几秒甚至几十秒才出一轮结果。
  • 副作用不可控 —— 比如测试一个「删除用户」接口,真的把数据库数据删掉了。

这些问题说白了,都因为我们的测试代码依赖了真实的外部服务。我有个项目经历过线上事故,测试环境覆盖不全,结果某个接口改了个字段名称,上线直接崩溃。嗯,从那以后我就下定决心,必须把 Mock 引入到测试体系里。

**小提示**:Mock 不是偷懒,是让你在最干净的环境里验证业务逻辑,把不确定性降到最低。

单元测试 vs 集成测试:分清楚再动手

很多人分不清这两个概念,我建议用一张表格来看区别:

维度单元测试集成测试
目标验证单个类/方法的行为验证多个模块之间的协作
依赖尽量无依赖,或使用 Mock 替代可依赖真实组件(数据库、网络等)
运行速度毫秒级,极快秒级或更慢
稳定性高,不受外部环境影响低,网络和服务状态会影响结果
使用场景Repository、ViewModel 等业务逻辑API 真实调用、数据库读写等

你想想看,如果每个测试都去调真实接口,跑一轮几百个用例得多久?我见过团队用集成测试当单元测试用,结果 CI 管道动不动就超时,开发人员怨声载道。

**避坑指南**:
我曾经在一个项目中把所有测试都写成集成测试,后来重构时改个 ViewModel 都得修十几个测试。教训就是:单元测试要轻量,Mock 要到位,别把耦合带到测试里。

Mock 适配器在这中间扮演什么角色?

Retrofit 官方提供了 Mock 适配器,它的核心能力很简单——拦截网络请求,直接返回预设的响应,不走真实 HTTP 调用。说白了,就是让你在没有后端的情况下,也能把前端的网络层测透。

我个人习惯用 Mock 适配器来做两件事:

  1. 单测中的快速 Mock:给每个 API 定义好正常返回、异常返回、空返回等场景,测试 ViewModel 或 Repository 能否正确处理。
  2. 集成测试中的依赖替换:比如你想测试整个登录流程,但不想真往认证服务器发请求,就可以用 Mock 适配器模拟一个假的 返回。

为什么不用别的 Mock 库呢?因为 Retrofit 的 Mock 适配器是原生支持的,配置文件少,使用简单,还和我们常用的 OkHttp、Gson 无缝衔接。你看下面这个代码:

val mockRetrofit = Retrofit.Builder()
    .baseUrl("http://localhost/")
    .addConverterFactory(GsonConverterFactory.create())
    .client(OkHttpClient.Builder()
        .addInterceptor(MockInterceptor()) // 自定义拦截器做 Mock
        .build())
    .build()

但这里有个问题,用拦截器做 Mock 虽然灵活,但需要自己写匹配逻辑。Retrofit 官方的 Mock 适配器更优雅——它直接继承了 CallAdapter.Factory,你只需指定一个 BehaviorDelegate,就能控制每次请求的返回。

一句话总结:
单元测试保证「代码逻辑正确」,集成测试保证「系统协作正常」。Mock 适配器让单元测试真正脱离网络依赖,跑得又快又稳。

本章知识体系总览

下面的 SVG 图帮你理清 Mock 适配器在整个测试流程中的位置和作用。

第2章:为什么需要Mock适配器 测试痛点 • 接口未就绪 • 网络不稳定 • 数据难构造 • 测试速度慢 • 副作用不可控 Mock适配器 拦截网络请求 返回预设响应 零网络依赖 快速可重复 支持多种场景 解决 单元测试 验证单个类/方法,依赖Mock 集成测试 验证模块协作,依赖真实服务 核心原则 • 单元测试必须快速、稳定、无副作用 → 用Mock适配器 • 集成测试可以慢一点,但要真实 → 走真实网络 开发阶段:快速验证API CI阶段:跑单测不卡顿 测试阶段:懒造边界数据

图中清晰展示:测试痛点 → Mock 适配器(解决方案)→ 单元测试/集成测试的分类应用。有了 Mock 适配器,你可以在开发阶段就写好完备的测试用例,后端接口变了也不用慌,改改 Mock 数据就行。

什么时候该用,什么时候不该用?

我再说一个实用建议。Mock 适配器不是万能的,它适合以下场景:

  • 单元测试 Repository 和 ViewModel—— 用 Mock 模拟成功/失败/异常三种状态,覆盖率拉升很快。
  • UI 测试中的网络层替换 —— 你写 Espresso 测试时,不希望每次请求都等真实的服务器响应吧?Mock 一下就行。
  • 演示或调试 —— 会议演示时,网络不好翻车太尴尬。提前用 Mock 适配器写好假数据,稳定展示。

但下面这些情况,就不要用 Mock:

  • 想验证真实服务器行为 —— 比如检查 API 的响应结构是否真的变化,那就必须用集成测试走真实请求。
  • 性能压测 —— Mock 不经过网络,测不出实际瓶颈。
**我的经验**:
团队一般把单元测试覆盖率目标定在 80% 以上,其中网络层相关的全部用 Mock 适配器来做。集成测试只覆盖关键路径,数量控制在 10 个以内,这样 CI 跑一次全量测试不会超过 5 分钟。

本章小结

我们得明确一个认知:测试的本质是验证逻辑正确性,而不是验证服务是否在线。Mock 适配器帮我们切断了外部的干扰,让测试回归本源。下一阶段我们就开始动手搭建它,你准备好了吗?