这些库构成了 JavaScript 测试生态的核心基石。jest 是开箱即用的全能框架,mocha 是高度灵活的测试运行器,chai 提供多样的断言风格,sinon 专注于函数模拟与间谍,而 jasmine 则是经典的行为驱动开发套件。它们共同解决了单元测试中的执行、验证和隔离问题。
在构建可靠的 JavaScript 应用时,测试工具的选择直接影响开发效率和代码质量。jest、mocha、chai、jasmine 和 sinon 是生态中最核心的五个包,但它们扮演的角色截然不同。有些是全能框架,有些是专用工具。让我们从架构、语法和实际场景出发,深入对比它们的差异。
jest 是开箱即用的全能解决方案。
// jest: 所有功能内置
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
jasmine 也是全能框架,但更经典。
// jasmine: 内置全局函数
describe('Sum', function() {
it('adds 1 + 2 to equal 3', function() {
expect(sum(1, 2)).toEqual(3);
});
});
mocha 是灵活的测试运行器。
chai 和 sinon 使用。// mocha: 仅定义测试结构
describe('Sum', function() {
it('adds 1 + 2 to equal 3', function() {
// 断言需引入 chai
});
});
chai 是专用断言库。
mocha 等运行器配合。// chai: 提供断言能力
expect(sum(1, 2)).to.equal(3);
sinon 是专用模拟库。
mocha + chai 组合使用。// sinon: 提供模拟能力
const stub = sinon.stub(myObj, 'method');
jest 使用简洁的 expect。
// jest: 链式断言
expect(user.name).toBe('Alice');
expect(list).toContain('item');
chai 提供自然语言风格的断言。
expect) 和 TDD (assert) 风格。// chai: 自然语言风格
expect(user).to.have.property('name').that.equals('Alice');
jasmine 使用内置的 expect。
// jasmine: 内置断言
expect(user.name).toEqual('Alice');
mocha 本身无断言。
chai 或 assert 模块。// mocha + chai: 组合使用
expect(result).to.be.ok;
sinon 侧重于行为验证。
// sinon: 行为验证
sinon.assert.calledOnce(stub);
jest 内置强大的模拟系统。
jest.fn() 创建函数间谍。jest.mock() 自动模拟模块。// jest: 内置模拟
const mockFn = jest.fn();
jest.mock('axios');
sinon 提供最细粒度的控制。
stub 替换函数实现。spy 监控函数调用。mock 设置期望值。// sinon: 细粒度控制
const stub = sinon.stub(api, 'get').resolves({ data: {} });
jasmine 内置基础的间谍功能。
spyOn 监控对象方法。// jasmine: 内置间谍
spyOn(api, 'get').and.returnValue(Promise.resolve({}));
mocha 无内置模拟。
sinon 或其他库。// mocha: 需引入 sinon
// 见 sinon 示例
chai 无模拟功能。
sinon 使用。// chai: 无模拟功能
// 仅用于验证结果
jest 自动处理 Promise。
async/await。// jest: 异步测试
test('fetches data', async () => {
const data = await fetchData();
expect(data).toBeDefined();
});
mocha 灵活支持多种异步模式。
done() 如果使用 callback。// mocha: 多种异步支持
it('fetches data', function(done) {
fetchData().then(() => done());
});
jasmine 支持 Promise 和 async。
async 包。// jasmine: 异步测试
it('fetches data', async () => {
const data = await fetchData();
expect(data).toBeDefined();
});
chai 不处理异步流程。
// chai: 仅断言结果
expect(result.status).to.equal(200);
sinon 提供假定时器。
sinon.useFakeTimers() 控制时间流逝。// sinon: 假定时器
const clock = sinon.useFakeTimers();
clock.tick(1000);
| 特性 | jest | mocha | chai | jasmine | sinon |
|---|---|---|---|---|---|
| 类型 | 全能框架 | 测试运行器 | 断言库 | 全能框架 | 模拟库 |
| 配置 | 零配置 | 需配置 | 需配合运行器 | 少量配置 | 需配合运行器 |
| 断言 | 内置 expect | 无 (配 Chai) | 丰富风格 | 内置 expect | 行为验证 |
| 模拟 | 内置 jest.fn | 无 (配 Sinon) | 无 | 内置 spyOn | 强大 stub |
| 适用 | React/Vue | Node/库 | 配合 Mocha | Angular/旧项目 | 复杂模拟 |
jest 是现代前端项目的首选 🚀。
它消除了工具链配置的痛苦,让团队专注于业务逻辑。适合绝大多数 React、Vue 和通用 JavaScript 项目。
mocha + chai + sinon 是经典组合 🛠️。
当你需要极度灵活的运行控制,或在 Node.js 库开发中需要精细的模拟策略时,这个组合依然强大。
jasmine 适合特定场景 📦。
如果你维护旧版 Angular 项目,或偏好不依赖外部配置的经典 BDD 风格,它依然可靠。
最终建议:除非有特殊的遗留系统限制或极端的定制化需求,否则在新项目中优先选择 jest。它的生态活跃度和开箱即用特性能显著降低维护成本。
选择 chai 当你配合 mocha 使用时,想要更丰富的断言语法(如 BDD 风格的 expect 或 TDD 风格的 assert)。它适合对断言表达力有特定要求的项目。
选择 jasmine 如果你维护传统的 Angular 项目,或偏好无需额外依赖的内置间谍函数和断言库。它适合习惯经典 BDD 风格且不愿配置 Jest 的团队。
选择 jest 如果你正在开发 React 或 Vue 项目,希望零配置启动并获得内置的快照测试和模拟功能。它适合追求开发效率和统一工具链的团队。
选择 mocha 如果你需要高度定制测试运行流程,或者在 Node.js 库开发中需要更灵活的异步控制。它适合需要组合不同断言库的复杂场景。
选择 sinon 当你在使用 mocha 而非 jest 时,需要强大的桩函数(stub)、间谍(spy)和模拟(mock)功能。它适合需要精细控制外部依赖的非 Jest 环境。
Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.
For more information or to download plugins, view the documentation.
Chai is an assertion library, similar to Node's built-in assert. It makes testing much easier by giving you lots of assertions you can run against your code.
chai is available on npm. To install it, type:
$ npm install --save-dev chai
You can also use it within the browser; install via npm and use the index.js file found within the download. For example:
<script src="./node_modules/chai/index.js" type="module"></script>
Import the library in your code, and then pick one of the styles you'd like to use - either assert, expect or should:
import { assert } from 'chai'; // Using Assert style
import { expect } from 'chai'; // Using Expect style
import { should } from 'chai'; // Using Should style
import 'chai/register-assert'; // Using Assert style
import 'chai/register-expect'; // Using Expect style
import 'chai/register-should'; // Using Should style
import { assert } from 'chai'; // Using Assert style
import { expect } from 'chai'; // Using Expect style
import { should } from 'chai'; // Using Should style
should(); // Modifies `Object.prototype`
import { expect, use } from 'chai'; // Creates local variables `expect` and `use`; useful for plugin use
mocha spec.js --require chai/register-assert.js # Using Assert style
mocha spec.js --require chai/register-expect.js # Using Expect style
mocha spec.js --require chai/register-should.js # Using Should style
Read more about these styles in our docs.
Chai offers a robust Plugin architecture for extending Chai's assertions and interfaces.
chai-pluginbrowser if your plugin works in the browser as well as Node.jsbrowser-only if your plugin does not work with Node.jsError constructor thrown upon an assertion failing.Thank you very much for considering to contribute!
Please make sure you follow our Code Of Conduct and we also strongly recommend reading our Contributing Guide.
Here are a few issues other contributors frequently ran into when opening pull requests:
chai.js build. We do it once per release.Please see the full Contributors Graph for our list of contributors.
Feel free to reach out to any of the core contributors with your questions or concerns. We will do our best to respond in a timely manner.
This project would not be what it is without the contributions from our prior core contributors, for whom we are forever grateful: