Skip to content

Node系列 · ORM:模拟数据

模拟数据(mock data)是开发效率的关键——前端不依赖后端接口就能跑通页面,后端不依赖真实业务就能跑测试。本章讲清楚两套场景的 mock 工具和最佳实践。

一、为什么要 mock

场景没 mock 的痛点有 mock 的好处
前端开发等后端接口写好才能开始后端 schema 定好就能并行开发
后端测试测试用例依赖真实数据库单元测试用内存 SQLite,毫秒级跑完
演示 / Demo没有真实数据用 Faker 生成逼真样本
边界条件难构造(如 100 万条记录)程序化生成指定规模数据

二、前端开发期 mock

2.1 mockjs(数据生成器)

最经典的前端 mock 库,按模板自动生成假数据:

bash
npm install mockjs
javascript
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 / @ipURL / 域名 / IP
@city / @province / @county地理
@pick(arr)从数组随机取 1 个
@guidUUID

2.2 json-server(假 REST API)

30 秒起一个完整 REST API:

bash
npm install -g json-server
json
{
  "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/ --save
javascript
// 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/faker
javascript
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-users

3.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"无缝切换