当后端还没准备好、而前端又等不起时,模拟数据 API 就是答案。Mock API 让前端团队可以基于稳定的契约交付 UI,而真实后端可以慢慢赶上;让移动端开发者无需真实授权令牌就能调试应用;也让任何人——尤其是 QA 团队——不必等待预发布环境部署就能测试新功能。本教程将介绍三种能力逐级增强的 Mock 模式,最后演示如何直接把 USA Data Tools REST API 当作模拟后端使用。
为什么需要 Mock API?
- 并行工作:前后端团队约定好契约;前端 Mock 它,后端实现它,双方交付都更快。
- 确定性:稳定的 Mock 每次运行都返回相同的数据,消除不稳定的测试。
- 边缘情况:Mock 可以刻意返回 500 和 422,让你的错误处理代码变得可测试。
- 隐私:迭代过程中没有真实客户数据离开生产环境。
模式一——静态托管的 JSON 文件
最简单的 Mock 就是一个由任意静态 HTTP 服务器托管的 JSON 文件目录。它适合只读端点。
mock-api/
users.json
users.42.json
addresses.json
用你喜欢的任何工具托管——Python 的 http.server、VS Code Live Server,或一行命令的 Vite 静态目录。前端代码通过环境变量请求 /mock-api/users.json 而不是 /api/users,这样之后可以切换基础 URL。
const API_BASE = process.env.REACT_APP_API_BASE || "/mock-api";
const users = await fetch(`${API_BASE}/users.json`).then(r => r.json());
局限:没有单条记录端点、没有分页、没有 PUT/POST。这种模式能覆盖 70% 的前端工作(列表和详情页),然后就力不从心了。
模式二——一个轻量 Node/Express 服务器
对于剩下的场景,写一个 50 行的 Express 服务器,用真实的 HTTP 语义返回夹具数据。状态码、查询参数解析和幂等的 POST 处理都免费获得。
// mock-server/server.js
import express from "express";
import { readFileSync } from "node:fs";
const users = JSON.parse(readFileSync("./fixtures/users.json", "utf8"));
const addresses = JSON.parse(readFileSync("./fixtures/addresses.json", "utf8"));
const app = express();
app.use(express.json());
// 带分页 + 搜索的列表
app.get("/api/users", (req, res) => {
const page = Number(req.query.page ?? 1);
const size = Number(req.query.size ?? 20);
const q = (req.query.q ?? "").toLowerCase();
const filtered = users.filter(u =>
!q || u.name.toLowerCase().includes(q) || u.email.includes(q)
);
const start = (page - 1) * size;
const data = filtered.slice(start, start + size);
res.json({
data,
page,
size,
total: filtered.length,
});
});
// 单条记录
app.get("/api/users/:id", (req, res) => {
const user = users.find(u => u.id === Number(req.params.id));
if (!user) return res.status(404).json({ error: "not found" });
res.json(user);
});
app.listen(8081, () => console.log("Mock API on http://localhost:8081"));
这个实现为前端团队提供了真实的 HTTP 语义——查询参数、状态码、content-type——代价只是大约一小时的敲键盘时间。
模式三——持续生成新鲜数据的 Mock
静态夹具会过时;上个 Sprint 的 10 条测试数据已经无法测出你刚做的无限滚动分页。使用 USA Data Tools API 按需为你的 Mock 填充数据。
// 每次 Mock 服务器启动时获取 50 条新鲜的美国记录
async function seedAddresses(count = 50) {
const r = await fetch(
`https://vic999.com/us-address/api/v1/address?count=${count}`,
{ headers: { Authorization: `Bearer ${process.env.USA_KEY}` } }
);
if (!r.ok) throw new Error(`seed failed: ${r.status}`);
const { data } = await r.json();
return data.map((a, i) => ({ id: i + 1, ...a }));
}
let cache = [];
app.get("/api/addresses", async (req, res) => {
if (cache.length === 0) cache = await seedAddresses(50);
res.json({ data: cache });
});
第一个请求到来时,Mock 会懒加载 50 条真实地址(邮编+州地理一致、区号有效的电话),然后从缓存中提供服务。重启 Mock 就能获得一批新数据——当你想要默认确定性、但每个 Sprint 又想要不同数据形态时非常有用。
提供边缘情况的响应
一个永远只返回 200 OK 的 Mock 测不出错误路径。用一个查询参数做分支,让测试可以选择进入失败模式:
app.get("/api/users/:id", (req, res) => {
if (req.query._force === "500") {
return res.status(500).json({ error: "forced_error" });
}
if (req.query._force === "slow") {
return setTimeout(() => res.json(users[0]), 5000);
}
const user = users.find(u => u.id === Number(req.params.id));
if (!user) return res.status(404).json({ error: "not_found" });
res.json(user);
});
现在你的前端测试可以请求 ?_force=500 来验证错误边界 UI 是否出现,或用 ?_force=slow 验证加载指示器是否显示。仅此一个模式就能堵住大多数前端的健壮性缺口。
为 Mock 契约编写文档
Mock 最大的成本是与真实后端之间的漂移。为 Mock 服务器配一份 OpenAPI 规范——哪怕手写——并双向验证:
- 从规范生成 Mock 响应(运行时返回符合 Schema 的数据)。
- 在 CI 中用规范校验真实后端(一个便宜的契约测试)。
一旦 Mock 与真实后端使用同一套 Schema,前端不在乎自己正在跟哪一个对话。
npx @stoplight/spectral-cli lint openapi.yaml --ruleset spectral:oas
接入 CI
jobs:
front-end-e2e:
runs-on: ubuntu-latest
services:
mock:
image: node:20
options: --entrypoint node
env:
USA_KEY: ${{ secrets.USA_KEY }}
ports: ["8081:8081"]
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run start:mock &
- run: npx playwright test
- run: npx @stoplight/spectral-cli lint openapi.yaml
Mock 作为服务启动,前端测试针对它运行,契约检查会在规范漂移时发出警告。当真实后端就绪后,切换环境变量即可——只要契约是诚实的,同样的测试就能通过。
三种方案如何取舍
| 模式 | 最适合 | 成本 |
|---|---|---|
| 静态 JSON | 只读的列表/详情 UI | 成本最低 |
| 轻量 Express 服务器 | POST/PUT、分页、搜索 | 一个下午 |
| USA API 填充数据 | 真实的大数据集 | API 密钥 + 50 行代码 |
跨团队交接
当后端团队准备就绪时,前端的 Mock 就变成了回归测试套件。经过 spectral 校验的规范成为契约;前端的 Playwright 套件针对真实后端运行,暴露任何漂移(“后端新增了必填字段”)。这就是为什么契约比 Mock 更重要——但 Mock 让你从第一天起就能开始检验契约。
提示:Mock 服务器天然是短命的。当真实后端上线后,不要扔掉 Mock——让它继续在仅本地可达的端口上运行,用于快速的离线迭代,以及故意触发那些真实后端不会按需产生的失败场景。
全新 SaaS 项目的实用配方
如果你从零开始:
- 为你需要的前 5 个端点编写 OpenAPI 规范。
- 启动由 USA Data Tools 地址 API 填充数据的 Express Mock 服务器。
- 通过
API_BASE环境变量把前端接上去。 - 添加
?_force=技巧,用于慢速/500/超时场景。 - 在 Mock 和真实后端的 CI 中都运行
spectrallint 作为契约测试。
这套模式在我们的项目中经受了多年的考验,可以从一个前端开发者扩展到 20 人的团队,而无需改变架构。
总结
模拟数据 API 不是走捷径——它是团队之间的交付契约,让所有人都能并行推进。先用几个 JSON 文件起步,需要 HTTP 语义时升级到 Express 服务器,再用地址生成器填充真正能测出边缘情况的数据集。搭配一个经过 Spectral 校验的 OpenAPI 规范,等真实后端就绪时,同一套测试无需任何重写即可直接运行。