Skip to content

Egg 为应用单元测试抽取了专门的 Mock 辅助包:@eggjs/mock(历史上也常被称为 egg-mock)。

@eggjs/mock 底层基于 mm(Mock Mate),提供更通用的打桩/猴子补丁能力。

安装

bash
npm i @eggjs/mock --save-dev

你可能会在旧文档/历史代码中看到 egg-mock。对 Egg 3.x,推荐直接使用 @eggjs/mock

快速开始

创建 app 实例

js
const mock = require('@eggjs/mock');

describe('test/controller/home.test.js', () => {
  let app;

  before(async () => {
    app = mock.app({ baseDir: 'path/to/your/app' });
    await app.ready();
  });

  after(() => app.close());
});

使用 bootstrap 避免重复初始化

js
const { app, mock, assert } = require('egg-mock/bootstrap');

describe('test/controller/home.test.js', () => {
  // 测试用例
});

bootstrap 会帮你做常用的初始化/清理流程,大多数项目直接用它即可。

创建 Context

js
it('should get a ctx', () => {
  const ctx = app.mockContext();
  assert(ctx.method === 'GET');
});

it('should mock ctx.user', () => {
  const ctx = app.mockContext({
    user: { name: 'fengmk2' },
  });
  assert(ctx.user.name === 'fengmk2');
});

每个用例后恢复 mock

在使用 mm / @eggjs/mock 时,需要记得恢复被 mock 的状态,避免污染其它用例:

js
const mm = require('mm');

afterEach(() => mm.restore());

如果你使用了 egg-mock/bootstrap,它会在 afterEach 中自动帮你 restore。

mm(Mock Mate)API

mm 是通用的 monkey-patch 工具库,@eggjs/mock 底层基于它实现,很多 Egg 的测试也会直接使用 mm

推荐使用 @eggjs/mock 的导出

为了保持 Egg 生态的一体性,建议优先使用 @eggjs/mock(egg-mock)导出的 mm:它与 mm 兼容,同时还包含 Egg 相关的 mock 能力。

js
// CJS
const { app, mm } = require('egg-mock/bootstrap');
// bootstrap 已经在 afterEach 中自动执行了 mm.restore()

// 或者
const mock = require('@eggjs/mock');
mock(target, 'prop', value);
mock.restore();

如果确实需要,也可以直接使用独立的 mm 包:

js
import mm, { restore } from 'mm';

核心能力

  • mm(target, property, value) / mm.mock(...):mock/打桩某个属性。
  • mm.restore() / restore():还原所有被 mock 的属性。
  • mm.isMocked(target, property):判断某个属性是否已被 mock。
  • mm.spy(target, method):只做 spy(记录调用次数/参数)。

当 mock 的属性是函数时,会自动附带 spy 字段:calledcalledArgumentslastCalledArguments

回调风格(Node callback)辅助

  • mm.data(target, method, data[, timeout]):回调返回 (null, data)
  • mm.datas(target, method, datas[, timeout]):回调返回 (null, ...datas)
  • mm.empty(target, method[, timeout]):回调返回 (null, null)
  • mm.error(target, method, error[, props|timeout][, timeout]):回调返回 error。
  • mm.errorOnce(...):类似 error,但只生效一次。

同步函数辅助

  • mm.syncData(target, method, value):直接 return。
  • mm.syncEmpty(target, method):return undefined
  • mm.syncError(target, method, error[, props]):直接 throw。

HTTP mock

  • mm.http.request(url, data[, headers][, delay]):mock http.request / http.get
  • mm.http.requestError(url[, reqError][, resError][, delay]):mock request/response error。
  • mm.https.request(...) / mm.https.requestError(...):同理(https)。

其它

  • mm.spawn(code, stdout, stderr[, timeout]):mock child_process.spawn
  • mm.classMethod(instance, method, mockFn):通过 prototype mock class method。

完整、最新的 API 仍建议以 mm 仓库为准: https://github.com/node-modules/mm

Born to build better enterprise frameworks and apps