Post

Mocha 测试框架

Mocha 测试框架

Mocha + Chai + Sinon

简介

  • Mocha:测试框架的核心,负责组织和运行测试用例。
  • Chai:强大的断言库,提供 BDD(行为驱动开发)和 TDD(测试驱动开发)风格的语法。
  • Sinon:mock 和 spy 工具的专家,擅长模拟外部依赖、跟踪函数调用。

构建一个完整的测试用例

安装

1
npm install --save-dev mocha chai sinon

项目代码(user.js

1
2
3
4
5
6
async function fetchUser(id) {
  const response = await fetch(`https://api.example.com/users/${id}`);
  return response.json();
}

module.exports = { fetchUser };

测试代码(test/user.test.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const { expect } = require('chai');
const sinon = require('sinon');
const { fetchUser } = require('../user');

describe('User API', () => {
  let fetchStub;

  beforeEach(() => {
    // 在每个测试前创建 stub
    fetchStub = sinon.stub(global, 'fetch');
  });

  afterEach(() => {
    // 清理 stub
    fetchStub.restore();
  });

  it('should fetch user data successfully', async () => {
    // 模拟 fetch 返回值
    const mockResponse = { json: () => ({ id: 1, name: 'Alice' }) };
    fetchStub.resolves(mockResponse);

    const result = await fetchUser(1);

    expect(fetchStub.calledOnce).to.be.true;
    expect(fetchStub.calledWith('https://api.example.com/users/1')).to.be.true;
    expect(result).to.deep.equal({ id: 1, name: 'Alice' });
  });

  it('should handle fetch errors', async () => {
    // 模拟 fetch 失败
    fetchStub.rejects(new Error('Network Error'));

    try {
      await fetchUser(1);
      expect.fail('Expected fetchUser to throw an error');
    } catch (err) {
      expect(err.message).to.equal('Network Error');
    }
  });
});

运行测试

package.json 中添加:

1
2
3
"scripts": {
  "test": "mocha test/**/*.js"
}

然后执行 npm test,可以看到测试结果。

协同工作

  • Mocha:通过 describeit 组织测试结构,支持 async/await,并提供 beforeEachafterEach 钩子管理测试状态。
    • Mocha 支持 --timeout 调整默认 2000ms 的超时时间。对于不稳定的异步测试,可以用 --retries 重试。
  • Chai:使用 expect 提供直观的断言,比如 to.be.trueto.deep.equal,让测试意图一目了然。
  • Sinon:通过 stub 模拟 fetch,控制测试环境,避免真实网络请求,确保测试的可重复性。
This post is licensed under CC BY 4.0 by the author.