Node系列 · ORM:模拟数据
模拟数据(mock data)是开发效率的关键——前端不依赖后端接口就能跑通页面,后端不依赖真实业务就能跑测试。本章讲清楚两套场景的 mock 工具和最佳实践。
一、为什么要 mock
| 场景 | 没 mock 的痛点 | 有 mock 的好处 |
|---|---|---|
| 前端开发 | 等后端接口写好才能开始 | 后端 schema 定好就能并行开发 |
| 后端测试 | 测试用例依赖真实数据库 | 单元测试用内存 SQLite,毫秒级跑完 |
| 演示 / Demo | 没有真实数据 | 用 Faker 生成逼真样本 |
| 边界条件 | 难构造(如 100 万条记录) | 程序化生成指定规模数据 |
二、前端开发期 mock
2.1 mockjs(数据生成器)
最经典的前端 mock 库,按模板自动生成假数据:
bash
npm install mockjsjavascript
const Mock = require('mockjs');
// 生成一条随机用户
Mock.mock({
id: '@id',
name: '@cname', // 中文姓名
email: '@email',
avatar: '@image("100x100")',
age: '@integer(18, 65)',
address: '@city(true)', // 中国省份+城市
createdAt: '@datetime',
});
// {
// id: '620000192302020987',
// name: '张伟',
// email: 'a@b.com',
// ...
// }
// 批量生成列表
const data = Mock.mock({
'list|100': [{ // 生成 100 条
id: '@id',
name: '@cname',
'status|1': ['active', 'inactive'], // 从数组随机取 1 个
}],
});mockjs 的语法模板丰富:
| 占位符 | 含义 |
|---|---|
@cname | 中文姓名 |
@name | 英文姓名 |
@email | 邮箱 |
@integer(min, max) | 整数 |
@float(min, max, dmin, dmax) | 浮点数 |
@date / @datetime | 日期 |
@image("WxH") | 随机图片 URL |
@url / @domain / @ip | URL / 域名 / IP |
@city / @province / @county | 地理 |
@pick(arr) | 从数组随机取 1 个 |
@guid | UUID |
2.2 json-server(假 REST API)
30 秒起一个完整 REST API:
bash
npm install -g json-serverjson
{
"users": [
{ "id": 1, "name": "Alice", "email": "alice@x.com" },
{ "id": 2, "name": "Bob", "email": "bob@x.com" }
],
"posts": [
{ "id": 1, "userId": 1, "title": "Hello" }
]
}bash
$ json-server --watch db.json --port 3000
GET /users # 列表
GET /users/1 # 详情
POST /users # 创建
PUT /users/1 # 全量更新
PATCH /users/1 # 部分更新
DELETE /users/1 # 删除
GET /users/1/posts # 关联查询自动支持过滤、排序、分页、关联查询——前端像调真接口一样调。
2.3 MSW(Mock Service Worker)
现代方案,拦截浏览器 fetch / axios 请求返回 mock 数据:
bash
npm install msw --save-dev
npx msw init public/ --savejavascript
// src/mocks/handlers.js
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('/api/users', () => {
return HttpResponse.json([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
]);
}),
http.post('/api/users', async ({ request }) => {
const body = await request.json();
return HttpResponse.json({ id: Date.now(), ...body }, { status: 201 });
}),
];javascript
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';
export const worker = setupWorker(...handlers);优点:拦截网络层而非 axios 层,业务代码完全无感知——切到真接口时改 baseURL 即可。
三、后端测试期 mock
3.1 Faker.js(生成器)
后端测试和 seed 数据最常用的库:
bash
npm install @faker-js/fakerjavascript
const { faker } = require('@faker-js/faker');
// 设置中文 locale
faker.locale = 'zh_CN';
const user = {
id: faker.datatype.uuid(),
name: faker.name.findName(),
email: faker.internet.email(),
phone: faker.phone.number(),
avatar: faker.image.avatar(),
createdAt: faker.date.recent(),
};
// 批量
const users = Array.from({ length: 100 }, () => ({
id: faker.datatype.uuid(),
name: faker.name.findName(),
email: faker.internet.email(),
}));3.2 Sequelize 种子数据(seed)
javascript
'use strict';
const { faker } = require('@faker-js/faker');
module.exports = {
up: async (queryInterface) => {
const users = Array.from({ length: 50 }, () => ({
id: faker.datatype.uuid(),
name: faker.name.findName(),
email: faker.internet.email(),
createdAt: new Date(),
updatedAt: new Date(),
}));
await queryInterface.bulkInsert('users', users, {});
},
down: async (queryInterface) => {
await queryInterface.bulkDelete('users', null, {});
},
};bash
npx sequelize-cli db:seed --seed 20240815-seed-users3.3 测试时用 SQLite 内存数据库
单元测试不要打真实 MySQL——用 SQLite 内存数据库,毫秒级建表:
javascript
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory:', { logging: false });
// 每个测试前同步模型
beforeEach(async () => {
await sequelize.sync({ force: true });
});
// 每个测试后断开
afterAll(async () => {
await sequelize.close();
});TIP
测试和生产用同一 ORM,不同数据库。Sequelize 模型在 MySQL 和 SQLite 上都能跑——业务代码不变,只换 connection。这是 ORM 跨数据库能力的最大价值。
四、选型决策树
需要 mock 数据?
├── 前端独立开发(不依赖后端)
│ ├── 简单 GET 数据 → json-server
│ ├── 复杂生成规则 → mockjs(自写 fetch wrapper)
│ └── 完整 fetch 拦截 → MSW(推荐现代方案)
│
└── 后端测试 / seed 数据
├── 单元测试 → SQLite 内存 + Faker.js
├── 集成测试 → Docker MySQL + Faker.js
└── seed 初始化 → sequelize-cli seed + Faker.js五、最佳实践
| 场景 | 推荐 |
|---|---|
| 前端独立开发 | MSW(最现代,拦截 fetch 业务无感) |
| 简单 mock 后端 | json-server(30 秒起步) |
| 复杂数据模板 | mockjs 或 @faker-js/faker |
| 单元测试 | SQLite 内存 + Faker.js |
| E2E 测试 | 真实数据库(docker-compose 起 MySQL) |
| Seed 数据 | sequelize-cli seed + Faker.js |
| 敏感字段 | 永远不 mock 真实用户信息 |
WARNING
mock 数据 ≠ 真实数据。生产环境加载种子数据用于演示前,记得:
- 不要用真实姓名 / 邮箱 / 手机号
- 标识字段加
[MOCK]前缀 - 准备好快速清空脚本
六、小结
- 前端 mock:
mockjs(模板生成)/json-server(REST API)/MSW(拦截 fetch,推荐) - 后端 mock:Faker.js 生成 + SQLite 内存数据库跑测试
- 测试期永远不依赖真实数据库——毫秒级 vs 数十秒差异
- mock 数据要避免使用真实个人信息(合规风险)
- ORM 跨数据库能力让"测试用 SQLite / 生产用 MySQL"无缝切换
