ava、jasmine、jest 和 mocha 都是 JavaScript 生态系统中用于编写和运行自动化测试的核心工具。它们帮助开发者验证代码逻辑、防止回归错误并确保应用稳定性。jest 以“开箱即用”的全能特性著称,集成了运行器、断言库和模拟功能;mocha 则提供极高的灵活性,允许开发者自由组合断言和模拟库;ava 专注于利用 Node.js 的并行能力加速测试执行;而 jasmine 作为老牌行为驱动开发(BDD)框架,常用于传统项目或 Angular 生态中。
在构建可靠的前端或 Node.js 应用时,选择合适的测试框架是架构决策中的关键一步。jest、mocha、ava 和 jasmine 都能帮你编写自动化测试,但它们的设计哲学、执行模型和开发体验截然不同。作为架构师,我们需要透过表面的语法差异,理解它们在工程实践中的真实表现。
测试运行器的核心任务是加载并执行测试文件。不同的框架对并发处理有不同的策略,这直接影响大型项目的测试速度。
jest 默认并行运行测试文件,但在单个文件内串行执行测试用例。它通过沙箱隔离测试环境。
// jest: 文件间并行,文件内串行
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
test('adds 2 + 2 to equal 4', () => {
expect(sum(2, 2)).toBe(4);
});
mocha 默认串行执行所有测试。它本身不提供并行运行功能,通常需要配合第三方工具(如 mocha-parallel-tests)或集群模式来实现并发。
// mocha: 默认串行执行
describe('Math Suite', function() {
it('adds 1 + 2 to equal 3', function() {
assert.equal(sum(1, 2), 3);
});
it('adds 2 + 2 to equal 4', function() {
assert.equal(sum(2, 2), 4);
});
});
ava 的核心优势是真正的并行执行。它会在单独的进程中运行每个测试文件,甚至可以在文件内并行运行异步测试,极大提升速度。
// ava: 真正的并行执行
import test from 'ava';
test('adds 1 + 2 to equal 3', async t => {
t.is(sum(1, 2), 3);
});
test('adds 2 + 2 to equal 4', async t => {
t.is(sum(2, 2), 4);
});
jasmine 类似 Mocha,默认串行执行。它专注于行为驱动开发(BDD)风格,执行模型较为传统。
// jasmine: 串行执行
describe('Math Suite', function() {
it('adds 1 + 2 to equal 3', function() {
expect(sum(1, 2)).toBe(3);
});
it('adds 2 + 2 to equal 4', function() {
expect(sum(2, 2)).toBe(4);
});
});
断言是测试的核心,用于验证结果是否符合预期。框架是否内置断言库决定了你的依赖复杂度。
jest 内置了强大的 expect 全局对象,支持链式调用和丰富的匹配器。
// jest: 内置 expect
test('object assignment', () => {
const data = { one: 1 };
data['two'] = 2;
expect(data).toEqual({ one: 1, two: 2 });
});
mocha 本身 不包含 断言库。你需要自行安装 chai、should.js 或使用 Node 内置的 assert 模块。
// mocha: 需引入外部断言 (以 Node assert 为例)
const assert = require('assert');
it('object assignment', function() {
const data = { one: 1 };
data['two'] = 2;
assert.deepStrictEqual(data, { one: 1, two: 2 });
});
ava 拥有自己的一套断言 API,通过测试对象 t 传递。它的设计简洁,不支持链式调用,强调明确性。
// ava: 通过 t 对象断言
import test from 'ava';
test('object assignment', t => {
const data = { one: 1 };
data['two'] = 2;
t.deepEqual(data, { one: 1, two: 2 });
});
jasmine 内置了 expect 断言库,风格与 Jest 非常相似(因为 Jest 早期基于 Jasmine)。
// jasmine: 内置 expect
it('object assignment', function() {
const data = { one: 1 };
data['two'] = 2;
expect(data).toEqual({ one: 1, two: 2 });
});
在单元测试中,隔离外部依赖(如 API 调用、数据库)至关重要。框架对 Mock 和 Spy 的支持程度直接影响测试编写的便利性。
jest 提供了一流的内置模拟功能。你可以轻松模拟函数、模块甚至定时器。
// jest: 内置 jest.fn() 和 jest.mock()
const mockFn = jest.fn();
mockFn('a');
expect(mockFn).toHaveBeenCalledWith('a');
jest.mock('axios');
mocha 没有内置模拟功能。社区标准做法是搭配 sinon 库使用。
// mocha: 通常搭配 sinon
const sinon = require('sinon');
it('calls callback', function() {
const callback = sinon.spy();
process(callback);
sinon.assert.calledOnce(callback);
});
ava 同样不内置模拟功能,推荐结合 sinon 或 testdouble 使用。这保持了核心库的轻量。
// ava: 搭配 sinon
import test from 'ava';
import sinon from 'sinon';
test('calls callback', t => {
const callback = sinon.spy();
process(callback);
t.true(callback.calledOnce);
});
jasmine 内置了 spies 功能,无需额外库即可监控函数调用。
// jasmine: 内置 spyOn
it('calls callback', function() {
const callback = jasmine.createSpy('callback');
process(callback);
expect(callback).toHaveBeenCalled();
});
现代测试框架通常提供快照测试(Snapshot Testing)来防止 UI 或数据结构意外变更。
jest 以“零配置”闻名,内置快照测试功能。只需一个命令即可生成和比对快照。
// jest: 内置快照
test('snapshot', () => {
const component = renderComponent();
expect(component).toMatchSnapshot();
});
mocha 不支持快照测试。如果需要此功能,必须引入第三方插件(如 jest-snapshot 的独立版或 chai-jest-snapshot)。
// mocha: 需引入插件支持快照
// 无原生代码示例,需配置 chai-jest-snapshot 等插件
ava 内置了快照测试功能,用法与 Jest 类似,但存储格式和命令略有不同。
// ava: 内置快照
import test from 'ava';
test('snapshot', t => {
t.snapshot({ title: 'Hello' });
});
jasmine 原生不支持快照测试。通常需要借助 jasmine-snapshots 等社区插件来实现。
// jasmine: 需引入插件
// 无原生代码示例,依赖社区扩展
尽管实现方式不同,这四个框架在核心目标上是一致的。它们都支持异步测试、提供钩子函数(Hooks)来管理生命周期,并且都能集成到 CI/CD 流程中。
所有框架都支持 Promise 和 async/await,这是现代 JavaScript 测试的标配。
// jest
test('fetches data', async () => {
const data = await fetchData();
expect(data).toBeDefined();
});
// mocha
it('fetches data', async function() {
const data = await fetchData();
assert.ok(data);
});
// ava
test('fetches data', async t => {
const data = await fetchData();
t.truthy(data);
});
// jasmine
it('fetches data', async function() {
const data = await fetchData();
expect(data).toBeDefined();
});
它们都提供了 beforeEach、afterEach 等钩子,用于在测试前后清理状态或设置环境。
// 所有框架语法类似
beforeEach(() => {
// 重置数据库或状态
resetDatabase();
});
都支持只运行特定测试(如 test.only 或 it.only),方便调试单个用例。
// jest/mocha/jasmine
test.only('debug this', () => { ... });
// ava
test.only('debug this', t => { ... });
| 特性 | jest | mocha | ava | jasmine |
|---|---|---|---|---|
| 执行方式 | 并行 (文件级) | 串行 (默认) | 并行 (进程级) | 串行 (默认) |
| 断言库 | ✅ 内置 (expect) | ❌ 需外部 (如 Chai) | ✅ 内置 (t.is) | ✅ 内置 (expect) |
| 模拟功能 | ✅ 内置 (jest.fn) | ❌ 需外部 (如 Sinon) | ❌ 需外部 (如 Sinon) | ✅ 内置 (spyOn) |
| 快照测试 | ✅ 内置 | ❌ 需插件 | ✅ 内置 | ❌ 需插件 |
| 配置复杂度 | 低 (零配置) | 高 (自由组合) | 中 (约定优于配置) | 低 (简单配置) |
| 主要优势 | 功能全面,DX 好 | 灵活,可定制 | 速度快,隔离好 | 经典,依赖少 |
jest 就像一把瑞士军刀 🇨🇭 —— 它几乎包含了你需要的所有功能。对于大多数 React、Vue 或 Node.js 新项目,它是默认的最佳选择。它的生态最丰富,遇到问题最容易找到解决方案。
mocha 更像是一个精密的工具箱 🧰 —— 它只提供核心运行器,其余工具由你挑选。适合那些对构建流程有严格控制,或者已经积累了大量基于 Chai/Sinon 测试代码的企业级项目。
ava 是一台高性能引擎 🏎️ —— 如果你的测试套件运行时间过长,或者你担心测试之间的状态污染,Ava 的并行和隔离模型能带来显著改善。它适合对性能敏感的大型代码库。
jasmine 是一位经验丰富的老兵 🎖️ —— 它在 Angular 旧版本项目中非常常见。除非你正在维护这类项目,否则在新项目中选择 Jest 通常会获得更好的长期支持。
最终建议:对于 90% 的现代前端项目,jest 是最稳妥的起点。只有当你有明确的性能瓶颈(选 ava)或特殊的架构约束(选 mocha)时,才考虑其他选项。
选择 ava 如果你的测试套件非常庞大且运行缓慢,需要利用并行执行来节省时间。它强制测试隔离,避免状态污染,适合对测试稳定性和执行效率有极高要求的场景。
选择 jasmine 如果你正在维护一个传统的 Angular 项目,或者偏好经典的 BDD 风格且不需要复杂的构建配置。它依赖较少,但在现代前端生态中的新功能支持上不如 Jest 活跃。
选择 jest 如果你希望拥有一个零配置、功能全面的测试解决方案。它内置了断言、模拟、代码覆盖率和快照测试,非常适合 React 项目或需要快速搭建测试环境的新项目。
选择 mocha 如果你需要高度定制化的测试架构,或者正在维护一个已经基于 Chai 和 Sinon 构建测试体系的老项目。它不强制绑定任何断言库,适合对测试流程有精细控制需求的团队。
Please support our friend Vadim Demedes and the people in Ukraine.

AVA is a test runner for Node.js with a concise API, detailed error output, embrace of new language features and thread isolation that lets you develop with confidence 🚀
Watch this repository and follow the Discussions for updates.
Read our contributing guide if you're looking to contribute (issues / PRs / etc).

Translations: Español, Français, Italiano, 日本語, 한국어, Português, Русский, 简体中文
To install and set up AVA, run:
npm init ava
Your package.json will then look like this (exact version notwithstanding):
{
"name": "awesome-package",
"type": "module",
"scripts": {
"test": "ava"
},
"devDependencies": {
"ava": "^5.0.0"
}
}
Or if you prefer using Yarn:
yarn add ava --dev
Alternatively you can install ava manually:
npm install --save-dev ava
Make sure to install AVA locally. AVA cannot be run globally.
Don't forget to configure the test script in your package.json as per above.
Create a file named test.js in the project root directory.
Note that AVA's documentation assumes you're using ES modules.
import test from 'ava';
test('foo', t => {
t.pass();
});
test('bar', async t => {
const bar = Promise.resolve('bar');
t.is(await bar, 'bar');
});
npm test
Or with npx:
npx ava
Run with the --watch flag to enable AVA's watch mode:
npx ava --watch
AVA supports the latest release of any major version that is supported by Node.js itself. Read more in our support statement.
AVA adds code excerpts and clean diffs for actual and expected values. If values in the assertion are objects or arrays, only a diff is displayed, to remove the noise and focus on the problem. The diff is syntax-highlighted too! If you are comparing strings, both single and multi line, AVA displays a different kind of output, highlighting the added or missing characters.

AVA automatically removes unrelated lines in stack traces, allowing you to find the source of an error much faster, as seen above.
AVA automatically detects whether your CI environment supports parallel builds. Each build will run a subset of all test files, while still making sure all tests get executed. See the ci-parallel-vars package for a list of supported CI environments.
Please see the files in the docs directory:
We have a growing list of common pitfalls you may experience while using AVA. If you encounter any issues you think are common, comment in this issue.
t.plan()AVA, not Ava or ava. Pronounced /ˈeɪvə/: Ay (face, made) V (vie, have) A (comma, ago)
It's the Andromeda galaxy.
Concurrency is not parallelism. It enables parallelism.
![]() | ![]() |
|---|---|
| Mark Wubben | Sindre Sorhus |