Mock API 是什么?简单来说,它是一个“模拟版”的真实 API。它接收完全相同的请求,返回同样格式的响应,并且提供一个可调用的 URL。然而,在这个 URL 背后,并没有真正的数据库、业务逻辑或实际服务——你预先设定好它应该返回什么,它就原封不动地返回什么。
听起来似乎没什么特别,理念也确实简单。但它的价值在于:当后端服务尚未就绪、真实响应速度过慢、成本过高或不够可靠时,你依然可以基于它编写代码、开展测试。本文先讲清楚 Mock 的定义,再将其与容易混淆的概念区分开,最后探讨决定 Mock 行为的“静态”与“动态”两种模式。
Mock API 的本质
剥开表象,Mock API 本质上是一张“请求-响应”映射表。请求进入后,Mock 按照你设定的规则进行匹配,选择一条响应返回。除非你额外要求,中间不涉及任何计算。
一个 Mock 包含三部分:接口——路由、方法和参数,必须与真实 API 完全一致;响应定义——返回的 Body、状态码和 Header;匹配逻辑——Mock 如何决定某个请求对应哪个响应,从简单的路径匹配到基于查询参数或 Header 的分支规则。
由于接口与真实 API 一致,调用 Mock 的代码根本意识不到自己在与假服务交互。只需更换 Base URL,同一个客户端就能连接到真实服务。这种可互换性,正是它的核心价值所在。
搞清楚 Mock API 不是什么也至关重要。它不是缓存——缓存存储的是真实响应,而 Mock 是虚构的。它不是沙箱——供应商沙箱运行的是简化版的真实逻辑,Mock 根本不执行逻辑。它也不是分级环境——Staging 是完整部署的真实系统。Mock 比三者都轻量:它只是一个 API 的“前门”,背后只有预定义的答案,别无他物。
Mock 与 Stub 的区别
很多人将 “Mock” 和 “Stub” 混用,但在测试领域,它们的含义并不相同。
Stub(桩) 更为简单:为调用返回一个预设答案,仅此而已。你向它请求一个用户,它返回一个固定的用户。Stub 不关心自己被调用了多少次、如何被调用。
在严格的测试定义中,Mock 还会验证交互:它能断言自己是否被调用过、调用了多少次、使用了哪些参数。调用方式不正确,Mock 可能直接导致测试失败——它不仅要提供数据,还要负责“监控”。
不过在日常的 API 开发中,两者的界限比较模糊,“Mock API” 通常将两者都涵盖在内。一个有用的说法是:Stub 负责回答,Mock 负责回答并观察。当你的测试只关心代码获取的数据时,采用 Stub 风格即可;当测试关心代码是否以正确方式发出正确调用时,就需要 Mock 的验证功能。
此外还有两个相近术语。Fake(伪对象) 是一个能工作但经过简化的实现(比如用内存数据库代替真实数据库),它包含逻辑,只是比较简单。Spy(间谍对象) 包装一个真实对象,记录其被调用的方式,但不改变行为。在 API 开发语境下,Mock API 最接近一个带可选验证功能、通过 HTTP 在真实 URL 上提供服务的 Stub。你无需死磕这些词汇,但了解这条光谱,日后阅读测试文档时就不易犯晕。
Mock API 与真实服务器
真实服务器和 Mock 服务器可以在同一个 URL 上、返回同样的 JSON,区别仅在于端点背后发生了什么。
| 特性 | Mock API | 真实服务器 |
|---|---|---|
| 端点背后 | 预定义的响应 | 实时逻辑和数据库 |
| 响应来源 | 你编写的规则 | 根据每个请求计算 |
| 数据 | 固定或生成的 | 真实的、持久化的 |
| 副作用 | 无 | 写入、扣费、发邮件 |
| 速度 | 快且稳定 | 随负载波动 |
| 正确性 | 符合你的定义 | 符合实际行为 |
真实服务器告诉你真相:运行的是真实代码,能够证明系统可以正常工作。然而它慢、有状态,还会产生真实的副作用——在上面做测试,一不小心就可能扣掉信用卡金额、发送真实邮件。
Mock 服务器只告诉你你设定好的内容。它快速、无副作用、完全可预测,非常适合开发和绝大多数测试。但 Mock 可能出错而自身无法察觉,因为它不执行真实逻辑。这就是最终仍要保留一部分测试针对真实服务器运行的原因。
静态 Mock 与动态 Mock
Mock 返回响应的方式主要有两种,选择哪种会直接影响使用体验。
静态 Mock 返回固定 Payload。你编写一次精确的 JSON,每次匹配的请求都能得到完全相同的 Body。它可预测,断言非常容易。弱点在于不够真实:一个硬编码的 Payload 很难暴露代码在处理长字符串、空数组或意外 Null 值时可能出现的 Bug。
动态 Mock 则为每个请求生成响应。不再返回固定的 "id": "user_1001",而是每次调用生成一个新的 UUID;不再返回同一个名字,而是每次换一个真实姓名。动态 Mock 通常由 Faker.js 这类数据生成语法驱动——字段名为 email,就生成邮件地址;created_at,就生成日期。它更真实,更容易暴露边界情况,缺点在于难以进行精确断言。
大多数团队两种都会使用。静态 Mock 用于单元测试——需要已知值,便于断言。动态 Mock 用于开发、演示,以及需要多样性而非固定答案的场景。
动态 Mock 还可以升级为条件 Mock:根据请求进行分支处理。对 /orders/404 返回 404,携带错误 Token 的请求返回 401,其他则返回 200。一个 Mock 端点就能覆盖正常路径和多种失败路径。这才是 Mock 在测试中真正发光的地方——它能复现真实服务器不会按需产生的错误响应。
Mock API 在开发流程中的位置
Mock API 在三个阶段特别有用。早期,前端和后端可以定好契约、并行开发,无需相互等待。测试期间,将你的代码与网络波动隔离开,还能触发真实服务器不会自然出现的错误响应。演示和原型制作中,它提供受控、可预测的数据,没有实时依赖,展示中途不会崩溃。
反复出现的风险是偏离(Drift)。Mock 是接口的一个快照,而接口会变化。真实 API 增加或重命名字段后,脱节的 Mock 仍沿用旧格式,测试依然通过——契约已不复存在。
解决方法:将 Mock 视为“派生”而非“创作”。从真实 API 发布的同一个 Schema 中生成 Mock,这样契约一旦变化,Mock 自动重新生成。手动编写的 Mock 会迅速老化,而按规范生成的 Mock 永远是最新的快照。
(这里可以提一个实践:像 Apifox 这样的工具,设计一次 API,Mock 端点就根据设计自动生成,并且根据字段名推断出逼真的数据。Mock、文档、契约测试都读取同一个源头,自然保持同步。)
常见问题解答
简单来说,什么是 Mock API?
Mock API 是一个模仿真实 API 的虚假接口。它暴露相同的路由,返回相同格式的响应,但背后没有真实逻辑或数据库。响应是预定义的,让你在真实服务存在之前就能针对接口构建和测试。
Mock 和 Stub 有什么区别?
Stub 只返回预设响应。在严格的测试意义上,Mock 还会验证交互——它可以检查调用次数和参数是否正确。Stub 回答问题,Mock 回答问题并监控你如何提问。
Mock API 与真实服务器有何不同?
Mock 返回预定义响应,没有实际计算,速度快、可预测、无副作用。真实服务器针对真实数据库运行实际逻辑,慢、有状态,但能证明系统真正可以工作。开发用 Mock,契约测试和端到端测试用真实服务器。
应该用静态 Mock 还是动态 Mock?
需要可预测的值进行断言(单元测试)时使用静态 Mock。需要真实、多样的数据来抓取边界情况(开发、演示)时使用动态 Mock。多数团队两者结合使用。
如何防止 Mock API 变得不准确?
根据真实 API 发布的 Schema 生成 Mock,而不是手动编写。契约一旦变化,Mock 自动重新生成。再配合定期对真实 API 进行契约测试,任何残留偏离都能及早发现。
