Mocha 是一个功能丰富的 JavaScript 测试框架,可在 Node.js 和浏览器中运行,使异步测试变得简单且有趣。 Mocha 测试按顺序运行,允许灵活且准确的报告,同时将未捕获的异常映射到正确的测试用例。 托管在 GitHub 上。
# 赞助商
在工作中使用 Mocha?询问您的经理或营销团队他们是否愿意帮助 支持 我们的项目。 您公司的徽标也将显示在 npmjs.com 和我们的 GitHub 存储库 上。
# 支持者
发现 Mocha 有用?成为 支持者 并通过每月捐款支持 Mocha。
# 特性
- 浏览器支持
- 简单的异步支持,包括 Promise
- 并行运行 Node.js 测试
- 测试覆盖率报告
- 字符串差异支持
- 用于运行测试的 JavaScript API
- 自动检测并为非 TTY 禁用颜色
- 异步测试超时支持
- 测试重试支持
- 特定于测试的超时
- 报告测试持续时间
- 突出显示缓慢的测试
- 文件观察者支持
- 全局变量泄漏检测
- 可以选择运行与正则表达式匹配的测试
- 自动退出以防止在活动循环中“挂起”
- 轻松元生成套件 和 测试用例
- 配置文件支持
- 节点调试器支持
- 节点原生 ES 模块支持
- 源映射支持
- 检测对
done()的多次调用 - 使用您想要的任何断言库
- 可扩展的报告,捆绑了 9 个以上的报告器
- 可扩展的测试 DSL 或“接口”
- before、after、beforeEach、afterEach 钩子
- 任意转译器支持(coffee-script 等)
- TextMate 捆绑包
# 目录
- 安装
- 入门
- 运行周期概述
- 检测对
done()的多次调用 - 断言
- 异步代码
- 同步代码
- 箭头函数
- 钩子
- 待处理测试
- 排他性测试
- 包含性测试
- 重试测试
- 动态生成测试
- 超时
- 差异
- 命令行用法
- 并行测试
- 根钩子插件
- 全局夹具
- 测试夹具决策树向导
- 接口
- 报告器
- Node.JS 原生 ESM 支持
- 在浏览器中运行 Mocha
- 配置 Mocha (Node.js)
test/目录- 错误代码
- 编辑器插件
- 示例
- 测试 Mocha
- 更多信息
# 安装
使用 npm 全局安装
$ npm install --global mocha
或作为项目的开发依赖项
$ npm install --save-dev mocha
从 v10.0.0 开始,Mocha 需要 Node.js v14.0.0 或更高版本。
# 入门
$ npm install mocha
$ mkdir test
$ $EDITOR test/test.js # or open with your favorite editor
在您的编辑器中
var assert = require('assert');
describe('Array', function () {
describe('#indexOf()', function () {
it('should return -1 when the value is not present', function () {
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});
回到终端
$ ./node_modules/mocha/bin/mocha.js
Array
#indexOf()
✓ should return -1 when the value is not present
1 passing (9ms)
在 package.json 中设置测试脚本
"scripts": {
"test": "mocha"
}
然后使用以下命令运行测试
$ npm test
# 运行周期概述
针对 v8.0.0 更新。
以下是 Mocha 在 Node.js 中运行时的“执行流程”的中级概述;“不太重要”的细节已被省略。
在浏览器中,测试文件由 <script> 标签加载,调用 mocha.run() 从第 9 步开始 下面。
# 串行模式
- 用户(就是您)执行
mocha - 加载来自配置文件的选项(如果存在)
- Mocha 处理提供的任何命令行选项(有关详细信息,请参阅有关 配置合并 的部分)
- 如果找到
node可执行文件的已知标志- Mocha 将在子进程中生成
node,并使用这些标志执行自身 - 否则,Mocha 不会生成子进程
- Mocha 将在子进程中生成
- Mocha 加载由
--require指定的模块- 如果以这种方式加载的文件包含已知的 Mocha 特定导出(例如,根钩子插件),Mocha 将“注册”这些导出
- 如果不是,Mocha 将忽略
--require’d 模块的任何导出
- Mocha 验证通过
--require或其他方式加载的任何自定义报告器或接口 - Mocha 发现测试文件;当没有给出文件或目录时,它会找到当前工作目录相对路径的
test目录(但不包括其子目录)中的扩展名为.js、.mjs或.cjs的文件 - (默认)bdd 接口 以无特定顺序加载测试文件,这些文件被赋予特定于接口的
global上下文(这就是例如describe()最终成为测试文件中的全局变量的方式)- 当加载测试文件时,Mocha 会执行其所有套件并找到——但不会执行——其中的任何钩子和测试。
- 顶级钩子、测试和套件都是“不可见”根套件的成员;整个进程只有一个根套件
- Mocha 运行 全局设置夹具(如果有)
- 从“根”套件开始,Mocha 执行
- 任何“beforeAll”钩子(对于根套件,这只会发生一次;请参阅 根钩子插件)
- 对于每个测试,Mocha 执行
- 任何“beforeEach”钩子
- 测试(并报告结果)
- 任何“afterEach”钩子
- 如果当前套件有子套件,请对每个子套件重复步骤 10;每个子套件继承其父级中定义的任何“beforeEach”和“afterEach”钩子
- 任何“afterAll”钩子(对于根套件,这只会发生一次;请参阅 根钩子插件)
- Mocha 打印最终摘要/结语(如果适用)
- Mocha 运行 全局拆卸夹具(如果有)
# 并行模式
- 重复步骤 1 到 6,来自上面的 串行模式,跳过报告器验证
- 找到的所有测试文件都被放入队列中(它们不会被主进程加载)
- Mocha 运行 全局设置夹具(如果有)
- Mocha 创建一个子进程池(“工作者”)
- 在工作者运行它接收的第一个测试之前,工作者通过以下方式“引导”自身
- 加载所有
--require’d 模块 - 注册任何根钩子插件
- 忽略全局夹具和自定义报告器
- 断言内置或自定义接口有效
- 加载所有
- 当工作者收到要运行的测试文件时,工作者会为单个测试文件创建一个新的 Mocha 实例,并且
- 工作者重复步骤 8,来自上面的 步骤
- 工作者重复步骤 10,来自上面的 步骤,但工作者不会直接报告测试结果;它将它们保存在内存缓冲区中
- 当工作者完成测试文件时,缓冲的结果将返回到主进程,主进程然后将它们提供给用户指定的报告器(默认情况下为
spec) - 工作者使自身可用于池;如果还有剩余的测试文件,池会将另一个测试文件提供给工作者运行
- Mocha 打印最终摘要/结语(如果适用)
- Mocha 运行 全局拆卸夹具(如果有)
# 检测对 done() 的多次调用
如果您使用基于回调的异步测试,如果多次调用 done(),Mocha 将抛出错误。 这对于捕获意外的双重回调非常有用。
it('double done', function (done) {
// Calling `done()` twice is an error
setImmediate(done);
setImmediate(done);
});
运行上面的测试将给出以下错误消息
$ ./node_modules/.bin/mocha mocha.test.js
✓ double done
1) double done
1 passing (6ms)
1 failing
1) double done:
Error: done() called multiple times
at Object.<anonymous> (mocha.test.js:1:63)
at require (internal/module.js:11:18)
at Array.forEach (<anonymous>)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:608:3
# 断言
Mocha 允许您使用任何您想要的断言库。 在上面的示例中,我们使用的是 Node.js 的内置 assert 模块——但通常,如果它抛出 Error,它将起作用! 这意味着您可以使用以下库
- should.js - 这些文档中展示的 BDD 样式
- expect.js -
expect()样式断言 - chai -
expect()、assert()和should样式断言 - better-assert - C 样式自文档化
assert() - unexpected - “可扩展的 BDD 断言工具包”
# 异步代码
通过向 it() 的测试回调添加一个参数(通常命名为 done),Mocha 将知道它应该等待此函数被调用以完成测试。 此回调接受 Error 实例(或其子类)或假值;任何其他内容都是无效用法,会抛出错误(通常会导致测试失败)。
describe('User', function () {
describe('#save()', function () {
it('should save without error', function (done) {
var user = new User('Luna');
user.save(function (err) {
if (err) done(err);
else done();
});
});
});
});
或者,直接使用 done() 回调(它将处理错误参数,如果存在)
describe('User', function () {
describe('#save()', function () {
it('should save without error', function (done) {
var user = new User('Luna');
user.save(done);
});
});
});
# 使用 Promise
或者,您可以返回一个 Promise,而不是使用 done() 回调。 如果您正在测试的 API 返回 Promise 而不是接受回调,这很有用
beforeEach(function () {
return db.clear().then(function () {
return db.save([tobi, loki, jane]);
});
});
describe('#find()', function () {
it('respond with matching records', function () {
return db.find({type: 'User'}).should.eventually.have.length(3);
});
});
后面的示例使用 Chai as Promised 进行流畅的 Promise 断言。
在 Mocha v3.0.0 及更高版本中,返回 Promise 和调用 done() 将导致异常,因为这通常是一个错误
const assert = require('assert');
// antipattern
it('should complete this test', function (done) {
return new Promise(function (resolve) {
assert.ok(true);
resolve();
}).then(done);
});
上面的测试将失败,显示 Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.。 在 v3.0.0 之前的版本中,对 done() 的调用实际上被忽略了。
# 使用 async / await
如果您的 JS 环境支持 async / await,您也可以像这样编写异步测试
beforeEach(async function () {
await db.clear();
await db.save([tobi, loki, jane]);
});
describe('#find()', function () {
it('responds with matching records', async function () {
const users = await db.find({type: 'User'});
users.should.have.length(3);
});
});
# 同步代码
在测试同步代码时,省略回调,Mocha 将自动继续进行下一个测试。
describe('Array', function () {
describe('#indexOf()', function () {
it('should return -1 when the value is not present', function () {
[1, 2, 3].indexOf(5).should.equal(-1);
[1, 2, 3].indexOf(0).should.equal(-1);
});
});
});
# 箭头函数
将 箭头函数(也称为“lambda”)传递给 Mocha 是不鼓励的。 Lambda 按词法绑定 this,并且无法访问 Mocha 上下文。 例如,以下代码将失败
describe('my suite', () => {
it('my test', () => {
// should set the timeout of this test to 1000 ms; instead will fail
this.timeout(1000);
assert.ok(true);
});
});
如果您不需要使用 Mocha 的上下文,lambda 应该可以工作。 请注意,如果最终需要,使用 lambda 将更难重构!
# 钩子
使用其默认的“BDD”样式接口,Mocha 提供了 before()、after()、beforeEach() 和 afterEach() 钩子。 这些应该用于设置先决条件并在测试后清理。
describe('hooks', function () {
before(function () {
// runs once before the first test in this block
});
after(function () {
// runs once after the last test in this block
});
beforeEach(function () {
// runs before each test in this block
});
afterEach(function () {
// runs after each test in this block
});
// test cases
});
测试可以出现在您的钩子之前、之后或与您的钩子交织在一起。 钩子将按定义的顺序运行,具体取决于情况;所有
before()钩子都会运行(一次),然后是任何beforeEach()钩子、测试、任何afterEach()钩子,最后是after()钩子(一次)。
# 描述钩子
任何钩子都可以使用可选的描述调用,这使得更容易查明测试中的错误。 如果钩子被赋予一个命名函数,则如果没有提供描述,将使用该名称。
beforeEach(function () {
// beforeEach hook
});
beforeEach(function namedFun() {
// beforeEach:namedFun
});
beforeEach('some description', function () {
// beforeEach:some description
});
# 异步钩子
所有钩子(before()、after()、beforeEach()、afterEach())都可以是同步或异步的,行为与常规测试用例非常相似。 例如,您可能希望在每次测试之前使用虚拟内容填充数据库
describe('Connection', function () {
var db = new Connection(),
tobi = new User('tobi'),
loki = new User('loki'),
jane = new User('jane');
beforeEach(function (done) {
db.clear(function (err) {
if (err) return done(err);
db.save([tobi, loki, jane], done);
});
});
describe('#find()', function () {
it('respond with matching records', function (done) {
db.find({type: 'User'}, function (err, res) {
if (err) return done(err);
res.should.have.length(3);
done();
});
});
});
});
# 根级别钩子
在测试文件的最顶层范围(在套件之外)定义的钩子是根钩子。
从 v8.0.0 开始,根钩子插件 是设置根钩子的首选机制。
# 延迟根套件
警告:延迟根套件与 并行模式 不兼容。
如果您需要在运行任何套件之前执行异步操作(例如,用于动态生成测试),您可以延迟根套件。 使用 --delay 标志运行 mocha。 这将附加一个特殊的回调函数 run() 到全局上下文
const assert = require('assert');
const fn = async x => {
return new Promise(resolve => {
setTimeout(resolve, 3000, 2 * x);
});
};
// instead of an IIFE, you can use 'setImmediate' or 'nextTick' or 'setTimeout'
(async function () {
const z = await fn(3);
describe('my suite', function () {
it(`expected value ${z}`, function () {
assert.strictEqual(z, 6);
});
});
run();
})();
# 待处理测试
“待定” — 就像“有人应该最终编写这些测试用例” — 待定测试用例是指那些*没有*回调函数的测试用例。
describe('Array', function () {
describe('#indexOf()', function () {
// pending test below
it('should return -1 when the value is not present');
});
});
待定测试将包含在测试结果中,并标记为待定。待定测试不被视为失败测试。
阅读包含测试部分,了解如何使用this.skip()有条件地将测试标记为待定的示例。
# 排他性测试
警告:排他性测试与并行模式不兼容。
排他性功能允许您通过在函数末尾添加.only()来*仅*运行指定的套件或测试用例。以下是如何仅执行特定套件的示例
describe('Array', function () {
describe.only('#indexOf()', function () {
// ...
});
});
注意:所有嵌套套件仍将执行。
以下是如何执行单个测试用例的示例
describe('Array', function () {
describe('#indexOf()', function () {
it.only('should return -1 unless present', function () {
// ...
});
it('should return the index when present', function () {
// ...
});
});
});
在 v3.0.0 之前,.only() 使用字符串匹配来决定要执行哪些测试;现在不再是这种情况。在 v3.0.0 或更高版本中,.only() 可以使用多次来定义要运行的测试子集
describe('Array', function () {
describe('#indexOf()', function () {
it.only('should return -1 unless present', function () {
// this test will be run
});
it.only('should return the index when present', function () {
// this test will also be run
});
it('should return -1 if called with a non-Array context', function () {
// this test will not be run
});
});
});
您也可以选择多个套件
describe('Array', function () {
describe.only('#indexOf()', function () {
it('should return -1 unless present', function () {
// this test will be run
});
it('should return the index when present', function () {
// this test will also be run
});
});
describe.only('#concat()', function () {
it('should return a new Array', function () {
// this test will also be run
});
});
describe('#slice()', function () {
it('should return a new Array', function () {
// this test will not be run
});
});
});
但测试将具有优先级
describe('Array', function () {
describe.only('#indexOf()', function () {
it.only('should return -1 unless present', function () {
// this test will be run
});
it('should return the index when present', function () {
// this test will not be run
});
});
});
注意:如果存在钩子,它们仍将执行。
请注意,不要将
.only()的用法提交到版本控制中,除非您真的想这样做!为此,可以在持续集成测试命令(或在 git precommit 钩子中)中使用--forbid-only选项运行 mocha。
# 包含测试
此功能是.only() 的反面。通过添加.skip(),您可以告诉 Mocha 忽略测试用例。任何被跳过的内容都将被标记为待定,并作为此类内容报告。以下是如何跳过单个测试的示例
describe('Array', function () {
describe('#indexOf()', function () {
it.skip('should return -1 unless present', function () {
// this test will not be run
});
it('should return the index when present', function () {
// this test will be run
});
});
});
您也可以将.skip() 放置在整个套件上。这等同于将.skip() 添加到套件中的所有测试。套件中的钩子也会被跳过。
describe('Array', function () {
describe.skip('#indexOf()', function () {
it('should return -1 unless present', function () {
// this test will not be run
});
});
});
注意:跳过套件中放置在钩子或测试之外的代码仍然会执行,因为 mocha 仍然会调用套件函数来构建套件结构以进行可视化。
最佳实践:使用
.skip()而不是注释掉测试。
您也可以使用this.skip() 在运行时跳过测试。如果测试需要无法事先检测到的环境或配置,则运行时跳过是合适的。例如
it('should only test in the correct environment', function() {
if (/* check test environment */) {
// make assertions
} else {
this.skip();
}
});
上面的测试将被报告为待定。同样重要的是要注意,调用this.skip() 将有效地中止测试。
最佳实践:为了避免混淆,在调用
this.skip()后,不要在测试或钩子中执行进一步的指令。
将上面的测试与以下代码进行对比
it('should only test in the correct environment', function() {
if (/* check test environment */) {
// make assertions
} else {
// do nothing
}
});
因为此测试什么也不做,所以它将被报告为通过。
最佳实践:不要什么也不做!测试应该进行断言或使用
this.skip()。
要以这种方式跳过多个测试,请在“before all”钩子中使用this.skip()
before(function() {
if (/* check test environment */) {
// setup code
} else {
this.skip();
}
});
这将跳过套件中的所有it、beforeEach/afterEach 和describe 块。before/after 钩子将被跳过,除非它们是在与包含this.skip() 的钩子相同的级别上定义的。
describe('outer', function () {
before(function () {
this.skip();
});
after(function () {
// will be executed
});
describe('inner', function () {
before(function () {
// will be skipped
});
after(function () {
// will be skipped
});
});
});
在 v7.0.0 中更新:在“after all”钩子中跳过测试是不允许的,并且会抛出异常。使用 return 语句或其他方法来中止钩子执行。
在 Mocha v3.0.0 之前,this.skip() 在异步测试和钩子中不受支持。
# 重试测试
您可以选择将失败的测试重试最多一定次数。此功能旨在处理端到端测试(功能测试/Selenium…),其中资源不容易被模拟/存根。不建议将此功能用于单元测试。
此功能确实会重新运行失败的测试及其相应的beforeEach/afterEach 钩子,但不会重新运行before/after 钩子。this.retries() 对失败的钩子没有影响。
注意:以下示例使用 Selenium webdriver(它覆盖了全局 Mocha 钩子,用于Promise 链)。
describe('retries', function () {
// Retry all tests in this suite up to 4 times
this.retries(4);
beforeEach(function () {
browser.get('http://www.yahoo.com');
});
it('should succeed on the 3rd try', function () {
// Specify this test to only retry up to 2 times
this.retries(2);
expect($('.foo').isDisplayed()).to.eventually.be.true;
});
});
# 动态生成测试
鉴于 Mocha 使用函数表达式来定义套件和测试用例,因此动态生成测试非常简单。不需要特殊语法——可以使用普通的 JavaScript 来实现类似于“参数化”测试的功能,您可能在其他框架中见过这种功能。
以下是一个示例
const assert = require('assert');
function add(args) {
return args.reduce((prev, curr) => prev + curr, 0);
}
describe('add()', function () {
const tests = [
{args: [1, 2], expected: 3},
{args: [1, 2, 3], expected: 6},
{args: [1, 2, 3, 4], expected: 10}
];
tests.forEach(({args, expected}) => {
it(`correctly adds ${args.length} args`, function () {
const res = add(args);
assert.strictEqual(res, expected);
});
});
});
上面的代码将生成一个包含三个规范的套件
$ mocha
add()
✓ correctly adds 2 args
✓ correctly adds 3 args
✓ correctly adds 4 args
在.forEach 处理程序内添加的测试通常与编辑器插件配合不好,尤其是“右键单击运行”功能。参数化测试的另一种方法是使用闭包生成它们。以下示例等同于上面的示例
describe('add()', function () {
const testAdd = ({args, expected}) =>
function () {
const res = add(args);
assert.strictEqual(res, expected);
};
it('correctly adds 2 args', testAdd({args: [1, 2], expected: 3}));
it('correctly adds 3 args', testAdd({args: [1, 2, 3], expected: 6}));
it('correctly adds 4 args', testAdd({args: [1, 2, 3, 4], expected: 10}));
});
使用top-level await,您可以在测试文件加载时以动态和异步的方式收集测试数据。
另请参阅--delay,了解没有top-level await 的 CommonJS 模块。
// testfile.mjs
import assert from 'assert';
// top-level await: Node >= v14.8.0 with ESM test file
const tests = await new Promise(resolve => {
setTimeout(resolve, 5000, [
{args: [1, 2], expected: 3},
{args: [1, 2, 3], expected: 6},
{args: [1, 2, 3, 4], expected: 10}
]);
});
// in suites ASYNCHRONOUS callbacks are NOT supported
describe('add()', function () {
tests.forEach(({args, expected}) => {
it(`correctly adds ${args.length} args`, function () {
const res = args.reduce((sum, curr) => sum + curr, 0);
assert.strictEqual(res, expected);
});
});
});
测试持续时间
许多报告器将显示测试持续时间并标记运行缓慢的测试(默认:75 毫秒),如 SPEC 报告器所示

测试持续时间有三个级别(如以下图像所示)
- 快速:在“慢”阈值的一半内运行的测试将以绿色显示持续时间(如果有的话)。
- 正常:超过阈值一半(但仍在阈值内)运行的测试将以黄色显示持续时间。
- 慢速:超过阈值运行的测试将以红色显示持续时间。
要调整被视为“慢速”的内容,可以使用slow() 方法
describe('something slow', function () {
this.slow(300000); // five minutes
it('should take long enough for me to go make a sandwich', function () {
// ...
});
});
# 超时
# 套件级别
套件级别超时可以应用于整个测试“套件”,也可以通过this.timeout(0) 禁用。这将被所有嵌套套件和未覆盖值的测试用例继承。
describe('a suite of tests', function () {
this.timeout(500);
it('should take less than 500ms', function (done) {
setTimeout(done, 300);
});
it('should take less than 500ms as well', function (done) {
setTimeout(done, 250);
});
});
# 测试级别
也可以应用特定于测试的超时,或者使用this.timeout(0) 完全禁用超时
it('should take less than 500ms', function (done) {
this.timeout(500);
setTimeout(done, 300);
});
# 钩子级别
也可以应用钩子级别超时
describe('a suite of tests', function () {
beforeEach(function (done) {
this.timeout(3000); // A very long environment setup.
setTimeout(done, 2500);
});
});
同样,使用this.timeout(0) 禁用钩子的超时。
在 v3.0.0 或更高版本中,传递给
this.timeout()的参数大于最大延迟值 将导致超时被禁用。在 v8.0.0 或更高版本中,this.enableTimeouts()已被删除。警告:对于异步测试,如果您通过this.timeout(0)禁用超时,然后没有调用done(),您的测试将静默退出。
# 差异
Mocha 支持断言库中任何抛出的AssertionError 的err.expected 和err.actual 属性。Mocha 将尝试显示预期结果与断言实际看到的之间的差异。以下是如何使用--inline-diffs 显示“字符串”差异的示例

# 命令行用法
mocha [spec..]
Run tests with Mocha
Commands
mocha inspect [spec..] Run tests with Mocha [default]
mocha init <path> create a client-side Mocha setup at <path>
Rules & Behavior
--allow-uncaught Allow uncaught errors to propagate [boolean]
-A, --async-only Require all tests to use a callback (async) or
return a Promise [boolean]
-b, --bail Abort ("bail") after first test failure [boolean]
--check-leaks Check for global variable leaks [boolean]
--delay Delay initial execution of root suite [boolean]
--dry-run Report tests without executing them [boolean]
--exit Force Mocha to quit after tests complete [boolean]
--fail-zero Fail test run if no test(s) encountered [boolean]
--forbid-only Fail if exclusive test(s) encountered [boolean]
--forbid-pending Fail if pending test(s) encountered [boolean]
--global, --globals List of allowed global variables [array]
-j, --jobs Number of concurrent jobs for --parallel; use 1 to
run in serial
[number] [default: (number of CPU cores - 1)]
-p, --parallel Run tests in parallel [boolean]
--retries Retry failed tests this many times [number]
-s, --slow Specify "slow" test threshold (in milliseconds)
[string] [default: 75]
-t, --timeout, --timeouts Specify test timeout threshold (in milliseconds)
[string] [default: 2000]
-u, --ui Specify user interface [string] [default: "bdd"]
Reporting & Output
-c, --color, --colors Force-enable color output [boolean]
--diff Show diff on failure
[boolean] [default: true]
--full-trace Display full stack traces [boolean]
--inline-diffs Display actual/expected differences
inline within each string [boolean]
-R, --reporter Specify reporter to use
[string] [default: "spec"]
-O, --reporter-option, Reporter-specific options
--reporter-options (<k=v,[k1=v1,..]>) [array]
Configuration
--config Path to config file [string] [default: (nearest rc file)]
-n, --node-option Node or V8 option (no leading "--") [array]
--package Path to package.json for config [string]
File Handling
--extension File extension(s) to load
[array] [default: ["js","cjs","mjs"]]
--file Specify file(s) to be loaded prior to root suite
execution [array] [default: (none)]
--ignore, --exclude Ignore file(s) or glob pattern(s)
[array] [default: (none)]
--recursive Look for tests in subdirectories [boolean]
-r, --require Require module [array] [default: (none)]
-S, --sort Sort test files [boolean]
-w, --watch Watch files in the current working directory for
changes [boolean]
--watch-files List of paths or globs to watch [array]
--watch-ignore List of paths or globs to exclude from watching
[array] [default: ["node_modules",".git"]]
Test Filters
-f, --fgrep Only run tests containing this string [string]
-g, --grep Only run tests matching this string or regexp [string]
-i, --invert Inverts --grep and --fgrep matches [boolean]
Positional Arguments
spec One or more files, directories, or globs to test
[array] [default: ["test"]]
Other Options
-h, --help Show usage information & exit [boolean]
-V, --version Show version number & exit [boolean]
--list-interfaces List built-in user interfaces & exit [boolean]
--list-reporters List built-in reporters & exit [boolean]
Mocha Resources
Chat: https://discord.gg/KeDn2uXhER
GitHub: https://github.com/mochajs/mocha.git
Docs: https://mocha.node.org.cn/
# --allow-uncaught
默认情况下,Mocha 将尝试捕获从运行测试中抛出的未捕获异常,并将这些异常报告为测试失败。使用--allow-uncaught 禁用此行为,并允许未捕获异常传播。通常会导致进程崩溃。
此标志在调试难以跟踪的异常时很有用。
# --async-only, -A
强制执行一项规则,即测试必须以“异步”方式编写,这意味着每个测试都提供一个done 回调或返回一个Promise。不符合要求的测试将被标记为失败。
# --bail, -b
导致 Mocha 在遇到第一个测试失败后停止运行测试。相应的“after each”和“after all”钩子将执行以进行潜在的清理。
--bail 不意味着--exit。
# --check-leaks
使用此选项让 Mocha 检查在运行测试时泄漏的全局变量。通过--global 选项指定可接受的全局变量(例如:--check-leaks --global jQuery --global MyLib)。
# --compilers
--compilers在 v6.0.0 中被删除。请参阅进一步的解释和解决方法。
# --dry-run
v9.0.0 中新增 报告测试,但不执行任何测试,包括测试和钩子。
# --exit
在 v4.0.0 中更新。
TL;DR:如果您的测试在升级到 Mocha v4.0.0 或更高版本后挂起,请使用--exit 进行快速(但不一定推荐)修复。
在 v4.0.0 版本之前,默认情况下,Mocha 会在完成执行所有测试后强制其自身进程退出。此行为会导致一组潜在问题;它表明测试(或夹具、工具、被测代码等)没有正确清理自身。最终,“脏”测试会导致误报或漏报结果。
“挂起”最常出现在服务器仍在监听端口或套接字仍然打开等情况下。它也可能是像失控的setInterval() 甚至是一个永远未完成的错误Promise。
v4.0.0(及更高版本)中的默认行为是--no-exit,而以前是--exit。
解决此问题的最简单方法是将--exit 传递给 Mocha 进程。这可能很耗时,因为问题并不总是很明显——但这样做是推荐的。
为了确保您的测试没有留下混乱,以下是一些入门想法
- 请参阅Node.js 调试指南
- 使用新的
async_hooksAPI (示例) - 尝试使用类似于wtfnode 的工具
- 使用
.only直到找到导致 Mocha 挂起的测试
# --fail-zero
v9.1.0 中新增 如果没有遇到测试,则使用
exit-code: 1失败测试运行。
# --forbid-only
强制执行一项规则,即测试不能是排他性的(例如,不允许使用describe.only() 或it.only())。
--forbid-only 导致 Mocha 在遇到排他性(“only’d”)测试或套件时失败,并且它将中止进一步的测试执行。
# --forbid-pending
强制执行一项规则,即测试不能被跳过(例如,不允许使用describe.skip()、it.skip() 或this.skip())。
--forbid-pending 导致 Mocha 在遇到跳过(“待定”)测试或套件时失败,并且它将中止进一步的测试执行。
# --global <variable-name>
在 v6.0.0 中更新;该选项是
--global,而--globals现在是别名。
定义一个全局变量名。例如,假设您的应用程序故意公开名为app 和YUI 的全局变量,您可能想要添加--global app --global YUI。
--global 接受通配符。您可以执行--global '*bar',它将匹配foobar、barbar 等。您也可以传递'*' 来忽略所有全局变量。
--global 可以接受逗号分隔的列表;--global app,YUI 等同于--global app --global YUI。
通过将此选项与--check-leaks 结合使用,您可以指定您期望泄漏到全局范围的已知全局变量的白名单。
# --retries <n>
将失败的测试重试n 次。
Mocha 默认情况下不会重试测试失败。
# --slow <ms>, -s <ms>
以毫秒为单位指定“慢速”测试阈值。Mocha 使用它来突出显示运行时间过长的测试用例。“慢速”测试不被视为失败。
注意:在默认的 spec 报告器中,执行时间为“慢”时间一半的测试将以黄色突出显示;执行时间为整个“慢”时间的测试将以红色突出显示。
# --timeout <ms>, -t <ms>
v6.0.0 中更新:使用 inspect 标志调用 Mocha 时,
--timeout 0将被隐式使用。不再需要--timeout 99999999。
指定测试用例超时时间,默认为两秒(2000 毫秒)。超过此时间的测试将被标记为失败。
要覆盖,您可以以毫秒为单位传递超时时间,或使用 s 后缀的值,例如,--timeout 2s 和 --timeout 2000 等效。
要禁用超时,请使用 --timeout 0。
注意:同步(阻塞)测试也受超时时间限制,但它们不会在代码停止阻塞之前完成。无限循环仍然是无限循环!
# --ui <name>, -u <name>
--ui 选项允许您指定要使用的界面,默认为 bdd。
# --color, -c, --colors
v6.0.0 中更新。
--colors现在是--color的别名。
“强制”启用彩色输出,或者通过 --no-color 强制禁用它。默认情况下,Mocha 使用 supports-color 模块来决定。
在某些情况下,某些以机器可读格式输出的报告器会明确抑制彩色输出。
# --diff
如果可能,在遇到断言失败时显示预期值和实际值之间的差异。
此标志不同寻常,因为它默认值为 true;使用 --no-diff 来抑制 Mocha 自己的 diff 输出。
一些断言库将提供自己的 diff,在这种情况下,无论默认值如何,都不会使用 Mocha 的 diff。
Mocha 自己的 diff 输出不符合任何已知标准,旨在供人类阅读。
v9.2.1 中新增
默认情况下,字符串在生成 diff 之前会被截断为 8192 个字符。这是为了防止大型字符串出现性能问题。
但是,在比较大型字符串时,这可能会使输出更难解释。因此,可以使用 --reporter-option maxDiffSize=[number] 配置此值。
值为 0 表示没有限制,默认值为 8192 个字符。
# --full-trace
启用“完整”堆栈跟踪。默认情况下,Mocha 尝试将堆栈跟踪提炼成更少噪音(但仍然有用)的输出。
此标志在调试 Mocha 或 Node.js 本身中疑似问题时很有用。
# --inline-diffs
启用“内联”diff,这是用于比较字符串的另一种输出方式。
在处理大型字符串时很有用。
如果断言库提供自己的 diff 输出,则不会执行任何操作。
# --reporter <name>, -R <name>
指定将使用的报告器,默认为 spec。
允许使用第三方报告器。例如,mocha-lcov-reporter 可以在安装后使用 --reporter mocha-lcov-reporter 使用。
# --reporter-option <option>, -O <option>, --reporter-options <option>
v6.0.0 中更新。可以多次指定。
--reporter-options现在是--reporter-option的别名。
以 <key>=<value> 格式提供特定于报告器的选项,例如,--reporter tap --reporter-option tapVersion=13。
并非所有报告器都接受选项。
可以指定为逗号分隔的列表。
# --config <path>
v6.0.0 中新增
指定 配置文件 的显式路径。
默认情况下,如果未指定 --config,Mocha 将搜索配置文件;使用 --no-config 来抑制此行为。
# --node-option <name>, -n <name>
v9.1.0 中新增
用于 Node.js 和 V8 选项。Mocha 通过生成新的子进程将这些选项转发给 Node.js。
选项在设置时不带前导破折号 --,例如 -n require=foo -n unhandled-rejections=strict
也可以指定为逗号分隔的列表:-n require=foo,unhandled-rejections=strict
# --opts <path>
v8.0.0 中移除。请改用 配置文件。
# --package <path>
v6.0.0 中新增
指定 package.json 文件 的显式路径(可能包含 mocha 属性中的配置)。
默认情况下,Mocha 会在当前工作目录或最近的祖先目录中查找 package.json,并将使用找到的第一个文件(无论它是否包含 mocha 属性);要抑制 package.json 查找,请使用 --no-package。
# --extension <ext>
具有此扩展名的文件将被视为测试文件。默认为 js。
指定 --extension 将删除 .js 作为测试文件扩展名;使用 --extension js 重新添加它。例如,要加载 .mjs 和 .js 测试文件,您必须提供 --extension mjs --extension js。
该选项可以多次给出。该选项接受逗号分隔的列表:--extension a,b 等效于 --extension a --extension b。
v8.2.0 中新增
--extension 现在支持多部分扩展名(例如,spec.js)、前导点 (.js) 以及它们的组合 (.spec.js);
# --file <file|directory|glob>
警告:
--file与 并行模式 不兼容。
明确包含要在加载其他测试文件之前加载的测试文件。--file 的多次使用是允许的,并将按给定的顺序加载。
如果您想声明(例如)在所有其他测试文件中的每个测试之前运行的钩子,这将很有用。
以这种方式指定的文件不受 --sort 或 --recursive 的影响。
以这种方式指定的文件应包含一个或多个套件、测试或钩子。如果不是这种情况,请考虑使用 --require。
# --ignore <file|directory|glob>, --exclude <file|directory|glob>,
明确忽略一个或多个测试文件、目录或 glob(例如,some/**/files*),否则这些文件将被加载。
可以多次指定。
v10.0.0 中新增:在 Windows 中始终使用正斜杠
/作为路径分隔符。
使用 --file 指定的文件不受此选项的影响。
# --recursive
在查找测试文件时,递归进入子目录。
请参阅 --extension 以定义哪些文件被视为测试文件。
# --require <module>, -r <module>
在加载用户界面或测试文件之前,需要一个模块。这对以下情况很有用
- 测试工具
- 增强内置函数或全局范围的断言库(例如 should.js)
- 编译器,例如通过 @babel/register 的 Babel 或通过 ts-node 的 TypeScript(使用
--require ts-node/register)。请参阅 Babel 或 TypeScript 工作示例。
以这种方式需要的模块预计会同步执行;Mocha 不会等待所需模块中的异步任务完成。
您不能使用 --require 来设置钩子。如果您想设置钩子以运行(例如)在每个测试之前运行,请使用 根钩子插件。
从 v8.0.0 开始,Mocha 支持 NodeJS 原生 ESM 的
--require。没有单独的--import标志。
# --sort, -S
警告:
--sort与 并行模式 不兼容。
使用 Array.prototype.sort 对测试文件(按绝对路径)进行排序。
# --watch, -w
在文件更改时重新运行测试。
--watch-files 和 --watch-ignore 选项可用于控制监视哪些文件以进行更改。
可以通过键入 ⓡ ⓢ ⏎ 手动重新运行测试(与 nodemon 的快捷键相同)。
# --watch-files <file|directory|glob>
v7.0.0 中新增
设置 --watch 时要监视的路径或 glob 列表。如果与给定 glob 匹配的文件发生更改或被添加或删除,mocha 将重新运行所有测试。
如果路径是目录,则将监视所有文件和子目录。
默认情况下,将监视当前目录中所有具有 --extension 提供的扩展名且未包含在 node_modules 或 .git 文件夹中的文件。
该选项可以多次给出。该选项接受逗号分隔的列表:--watch-files a,b 等效于 --watch-files a --watch-files b
# --watch-ignore <file|directory|glob>
v7.0.0 中新增
要从监视中排除的路径或 glob 列表。默认为 node_modules 和 .git。
要排除目录中的所有文件,最好使用 foo/bar 而不是 foo/bar/**/*。后者仍然会监视目录 foo/bar,但会忽略对该目录内容的所有更改。
该选项可以多次给出。该选项接受逗号分隔的列表:--watch-ignore a,b 等效于 --watch-ignore a --watch-ignore b
# --fgrep <string>, -f <string>
v6.0.0 中的重大更改;现在与
--grep相互排斥。
使 Mocha 仅运行标题包含给定 string 的测试。
与 --grep 相互排斥。
# --grep <regexp>, -g <regexp>
v6.0.0 中的重大更改;现在与
--fgrep相互排斥。
使 Mocha 仅运行与给定 regexp 匹配的测试,该测试在内部被编译为 RegExp。
例如,假设您有“api”相关的测试以及“app”相关的测试,如以下代码段所示;可以使用 --grep api 或 --grep app 来运行其中一个。对于套件或测试用例标题的任何其他部分也是如此,--grep users 也是有效的,甚至 --grep GET 也是有效的。
另一个带双引号的选项:--grep "groupA|groupB"。
对于更复杂的条件:--grep "/get/i"。一些 shell(例如 Git-Bash-for-Windows)可能需要:--grep "'/get/i'"。使用除 ignoreCase /i(尤其是 /g 和 /y)之外的标志可能会导致不可预测的结果。
describe('api', function () {
describe('GET /api/users groupA', function () {
it('respond with an array of users', function () {
// ...
});
});
});
describe('app', function () {
describe('GET /users groupB', function () {
it('respond with an array of users', function () {
// ...
});
});
});
与 --fgrep 相互排斥。
# --invert
使用 --grep 或 fgrep 指定的匹配的反向。
需要 --grep 或 --fgrep(但不能同时使用)。
# --inspect, --inspect-brk, inspect
启用 Node.js 的检查器。
使用 --inspect / --inspect-brk 启动 V8 检查器以与 Chrome 开发者工具一起使用。
使用 inspect 启动 Node.js 的内部调试器。
所有这些选项都是相互排斥的。
暗示 --timeout 0。
# --parallel, -p
v.8.0.0 中新增。
使用 --parallel 标志在工作池中运行测试。
每个测试文件将被放入队列中,并在工作程序可用时执行。
注意:--parallel 对 Mocha 的行为有一些影响,您必须注意。阅读有关 并行运行测试 的更多信息。
# --jobs <count>, -j <count>
v.8.0.0 中新增。
使用 --jobs <count> 指定工作池中最大进程数。
默认值为CPU 核心数减 1。
提示:使用 --jobs 0 或 --jobs 1 临时禁用 --parallel。
除非与 --parallel 一起使用,否则无效。
# 关于选项类型
在 v6.0.0 中更新。
Mocha 的 --help 输出中,每个标注为 [boolean] 类型的标志都可以通过在标志名称前添加 --no- 来取反。例如,--no-color 将禁用 Mocha 的颜色输出,默认情况下颜色输出是启用的。
除非另有说明,否则所有布尔标志默认值为 false。
# 关于 node 标志
mocha 可执行文件支持 node 可执行文件支持的所有适用标志。
这些标志根据您的 Node.js 版本而有所不同。
node 标志可以在 Mocha 的 配置 中定义。
v9.1.0 中新增 您还可以使用
--node-option将node标志传递给 Node.js。
# --enable-source-maps
Node.js v12.12.0 中新增
如果将 --enable-source-maps 标志传递给 mocha,则会收集源映射并使用它们为转译后的代码提供准确的堆栈跟踪
Error: cool
at Object.<anonymous> (/Users/fake-user/bigco/nodejs-tasks/build/src/index.js:27:7)
-> /Users/fake-user/bigco/nodejs-tasks/src/index.ts:24:7
# 关于 V8 标志
在 node --v8-options 的输出中列出的任何标志(不包括 --v8-options 本身)前添加 --v8- 以使用它。
V8 标志可以在 Mocha 的 配置 中定义。
v9.1.0 中新增 您还可以使用
--node-option将 V8 标志(不带--v8-)传递给 Node.js。
# 并行测试
v.8.0.0 中新增。
根据测试的数量和性质,您可能会发现以并行方式运行测试(使用 --parallel 标志)时会获得显著的性能提升。
对于许多用例,并行测试应该开箱即用。但是,您必须了解行为的一些重要含义。
注意:基于 Mocha 构建的第三方库的作者应该阅读本文!
# 报告器限制
由于以下报告器的性质,它们在以并行方式运行测试时无法工作
这些报告器期望 Mocha 在执行之前知道它计划运行多少个测试。此信息在并行模式下不可用,因为测试文件仅在即将运行时加载。
在串行模式下,测试结果将在它们发生时“流式传输”。在并行模式下,报告器输出被缓冲;报告将在每个文件完成后发生。实际上,报告器输出将以“块”形式出现(但否则将相同)。如果测试文件特别慢,则在运行时可能会出现明显的暂停。
# 排他性测试不允许
您不能在并行模式下使用 it.only、describe.only、this.only() 等。 这是因为与上面提到的不兼容的报告器相同的原因:在并行模式下,Mocha 不会在运行测试之前将所有文件和套件加载到内存中。
建议的解决方法
提示:如果您的配置文件中定义了并行模式,则可以通过使用
--no-parallel标志或减少作业数(例如,--jobs=0)来在命令行中临时禁用它。
# 文件顺序是非确定性的
在并行模式下,Mocha 不保证测试文件运行的顺序,也不保证哪个工作进程运行它们。
因此,以下依赖于顺序的选项不能在并行模式下使用
# 测试持续时间可变性
以并行模式运行测试自然会使用更多系统资源。操作系统可能需要额外的时间来调度和完成某些操作,具体取决于系统负载。因此,可能需要增加单个测试的超时时间,无论是 全局 还是 其他。
# “Bail” 是“尽力而为”
当与 --bail(或 this.bail())一起使用以在第一次失败后退出时,其他测试很可能在同一时间运行。Mocha 必须在退出之前关闭其工作进程。
同样,子进程可能会抛出未捕获的异常。当与 --allow-uncaught 一起使用时,Mocha 会将此异常“冒泡”到主进程,但仍然必须关闭其进程。
无论哪种方式,Mocha 都将“很快”中止测试运行。
# 根钩子不是全局的
注意:这仅适用于在并行模式下运行时。
根钩子是测试文件中未定义在套件内的钩子。使用 bdd 接口的示例
// test/setup.js
// root hook to run before every test (even in other files)
beforeEach(function () {
doMySetup();
});
// root hook to run after every test (even in other files)
afterEach(function () {
doMyTeardown();
});
当通过以下命令运行(在默认的“串行”模式下)时
mocha --file "./test/setup.js" "./test/**/*.spec.js"
setup.js 将首先执行,并为 ./test/**/*.spec.js 中找到的每个测试安装上面显示的两个钩子。
上面的示例在并行模式下不起作用。
当 Mocha 在并行模式下运行时,测试文件不共享相同的进程, 也不共享相同的 Mocha 实例。因此,在测试文件A 中定义的假设根钩子将不存在于测试文件B 中。
以下是一些建议的解决方法
- 在每个测试文件的顶部使用
require('./setup.js')或import './setup.js'。最适合那些不喜欢样板代码的人。 - 推荐:使用新的(也是从 v8.0.0 开始的)根钩子插件 系统,在“必需”文件中定义根钩子。
如果您需要只运行一次代码,请改用 全局夹具。
# 不支持浏览器
目前,并行模式仅在 Node.js 中可用。
# 第三方报告器的报告器 API 限制
第三方报告器在尝试访问 Test、Suite 和 Hook 对象中不存在的属性时可能会遇到问题。如果第三方报告器在并行模式下不起作用(但在串行模式下起作用),请 提交问题。
# 并行模式故障排除
如果您发现您的测试在使用 --parallel 运行时无法正常工作,要么耸耸肩继续前进,要么使用此方便的清单来使事情正常工作
- ✅ 确保您使用的是 支持的报告器。
- ✅ 确保您没有使用 其他不支持的标志。
- ✅ 仔细检查您的 配置文件;配置文件中设置的选项将与任何命令行选项合并。
- ✅ 查找测试中的根钩子(它们看起来像 这样)。将它们移到 根钩子插件 中。
- ✅ 您使用的任何断言、模拟或其他测试库是否使用根钩子?它们可能需要 迁移 以与并行模式兼容。
- ✅ 如果测试意外超时,您可能需要增加默认测试超时时间(通过
--timeout) - ✅ 确保您的测试不依赖于以特定顺序运行。
- ✅ 确保您的测试在自身之后清理;删除临时文件、句柄、套接字等。不要尝试在测试文件之间共享状态或资源。
# 关于并行测试的注意事项
某些类型的测试不太适合并行运行。例如,极其时间敏感的测试,或对有限资源池进行 I/O 请求的测试(例如打开端口,或自动化浏览器窗口,命中测试数据库或远程服务器等)。
免费层的云 CI 服务可能无法为其构建代理提供合适的多个核心的容器或虚拟机。关于 CI 中预期的性能提升:您的里程可能会有所不同。在 .mocharc.js 中使用条件检查 process.env.CI 可能会有所帮助,并根据需要调整作业数。
大于可用 CPU 核心数的 作业数 不太可能(但并非不可能)看到性能提升。也就是说,尝试不同的作业数——没有一种万能的解决方案,您测试的独特特征将决定最佳作业数;甚至可能更少的作业更快!
# 并行模式工作进程 ID
v9.2.0 中新增
并行模式启动的每个进程都分配了一个唯一的 ID,从第一个启动的进程的 0 到第 N 个进程的 N-1。可以通过环境变量 MOCHA_WORKER_ID 在测试中访问此工作进程 ID。例如,它可以用于为每个测试进程分配不同的数据库、服务端口等。
# 根钩子插件
v8.0.0 中新增
在某些情况下,您可能希望在每个文件中的每个测试之前(或之后)使用 钩子。这些被称为根钩子。在 v8.0.0 之前,实现此目的的方法是使用 --file 结合根钩子(参见 上面的示例)。这在 v8.0.0 中仍然有效,但在并行模式下无效!因此,强烈建议不要使用此方法运行根钩子,并且将来可能会弃用。
根钩子插件是一个通过 --require 加载的 JavaScript 文件,它“注册”一个或多个将在所有测试文件中使用的根钩子。
在浏览器中,您可以通过 rootHooks 对象直接设置根钩子:mocha.setup({ rootHooks: {beforeEach() {...}} }),参见 mocha.setup()
# 定义根钩子插件
根钩子插件文件是一个脚本,它通过 module.exports 导出 mochaHooks 属性。它通过 --require <file> 加载。
以下是一个使用 CJS 和 ESM 语法定义根钩子的简单示例。
# 使用 CommonJS
// test/hooks.js
exports.mochaHooks = {
beforeEach(done) {
// do something before every test
done();
}
};
# 使用 ES 模块
我们在这些示例中使用 .mjs 扩展名。
提示:如果您在使用 ES 模块时遇到问题,请参考 Node.js 文档。
// test/hooks.mjs
export const mochaHooks = {
beforeEach(done) {
// do something before every test
done();
}
};
注意:后面的示例将使用 ESM 语法。
# 可用的根钩子
根钩子适用于任何接口,但属性名称不会改变。换句话说,如果您使用的是 tdd 接口,则 suiteSetup 映射到 beforeAll,setup 映射到 beforeEach。
可用的根钩子及其行为
beforeAll:- 在串行模式(Mocha 的默认模式)下,在所有测试开始之前,仅运行一次
- 在并行模式下,在所有测试开始之前,为每个文件运行
beforeEach:- 在两种模式下,在每个测试之前运行
afterAll:- 在串行模式下,在所有测试结束后,仅运行一次
- 在并行模式下,在所有测试结束后,为每个文件运行
afterEach:- 在两种模式下,在每个测试之后运行
提示:如果您需要确保代码在任何模式下都只运行一次,请使用 全局夹具。
与其他钩子一样,this 指向当前上下文对象
// test/hooks.mjs
export const mochaHooks = {
beforeAll() {
// skip all tests for bob
if (require('os').userInfo().username === 'bob') {
return this.skip();
}
}
};
# 单个插件中的多个根钩子
为了组织目的,可以在单个插件中定义多个根钩子。例如
// test/hooks.mjs
export const mochaHooks = {
beforeEach: [
function (done) {
// do something before every test,
// then run the next hook in this array
},
async function () {
// async or Promise-returning functions allowed
}
]
};
# 根钩子插件可以导出一个函数
如果您需要执行一些逻辑 - 例如根据环境有条件地选择根钩子 - mochaHooks 可以是一个函数,它返回预期的对象。
// test/hooks.mjs
export const mochaHooks = () => {
if (process.env.CI) {
// root hooks object
return {
beforeEach: [
function () {
// CI-specific beforeEach
},
function () {
// some other CI-specific beforeEach
}
]
};
}
// root hooks object
return {
beforeEach() {
// regular beforeEach
}
};
};
如果您需要执行异步操作,mochaHooks 可以是返回 Promise 的。
// test/hooks.mjs
export const mochaHooks = async () => {
const result = await checkSomething();
// only use a root hook if `result` is truthy
if (result) {
// root hooks object
return {
beforeEach() {
// something
}
};
}
};
# 多个根钩子插件
可以通过多次使用 --require 来注册多个根钩子插件。例如,要注册 hooks-a.js 和 hooks-b.js 中的根钩子,请使用 --require hooks-a.js --require hooks-b.js。这些将按顺序注册(并运行)。
# 迁移测试以使用根钩子插件
要将使用根钩子的测试迁移到根钩子插件
- 找到您的根钩子(在套件外部定义的钩子 - 通常是
describe()回调)。 - 创建一个新文件,例如
test/hooks.js。 - 移动您的根钩子到
test/hooks.js中。 - 在
test/hooks.js中,将您的钩子设为导出的mochaHooks属性的成员。 - 在运行测试时使用
--require test/hooks.js(更好的是:使用一个 配置文件,其中包含{"require": "test/hooks.js"})。
例如,给定以下文件 test/test.spec.js,其中包含根钩子
// test/test.spec.js
beforeEach(function () {
// global setup for all tests
});
after(function () {
// one-time final cleanup
});
describe('my test suite', function () {
it('should have run my global setup', function () {
// make assertion
});
});
您的 test/hooks.js(对于此示例,一个 CJS 模块)应该包含
// test/hooks.js
exports.mochaHooks = {
beforeEach: function () {
// global setup for all tests
},
afterAll: function () {
// one-time final cleanup
}
};
注意:小心!
after变为afterAll,before变为beforeAll。
您原来的 test/test.spec.js 现在应该包含
// test/test.spec.js
describe('my test suite', function () {
it('should have run my global setup', function () {
// make assertion
});
});
运行 mocha --require test/hooks.js test/test.spec.js 将像以前一样运行(现在可以与 --parallel 一起使用)。
# 迁移库以使用根钩子插件
如果您是库维护者,并且您的库使用根钩子,您可以通过重构您的入口点来迁移
- 您的库应该始终导出一个
mochaHooks对象。 - 为了保持向后兼容性,仅当
global.beforeEach(或其他相关钩子)存在时才运行您的根钩子。 - 指示您的用户在运行
mocha时使用--require <your-package>。
# 全局夹具
v8.2.0 中新增
乍一看,全局夹具似乎与 根钩子 类似。但是,与根钩子不同,全局夹具
- 保证仅执行一次
- 在并行模式、观察模式和串行模式下工作相同
- 不与测试、套件或其他钩子共享上下文
# 全局设置夹具
要创建全局设置夹具,请从脚本中导出 mochaGlobalSetup,例如:
// fixtures.cjs
// can be async or not
exports.mochaGlobalSetup = async function () {
this.server = await startSomeServer({port: process.env.TEST_PORT});
console.log(`server running on port ${this.server.port}`);
};
…或 ES 模块
// fixtures.mjs
// can be async or not
export async function mochaGlobalSetup() {
this.server = await startSomeServer({port: process.env.TEST_PORT});
console.log(`server running on port ${this.server.port}`);
}
要使用它,请在通过 mocha --require fixtures.cjs(或您为文件命名的任何名称)运行 Mocha 时加载此文件。
请记住:您可以在 配置文件 中定义“需要”。
现在,在 Mocha 加载并运行您的测试之前,它将执行上述全局设置夹具,启动一个用于测试的服务器。但是,这不会在 Mocha 完成时关闭服务器!要做到这一点,请使用 全局拆卸夹具。
# 全局拆卸夹具
就像 全局设置夹具 一样,全局拆卸夹具可以通过从“需要”的脚本中导出来创建(我们可以将两种类型的夹具放在一个文件中)
// fixtures.cjs, cont'd
// can be async or not
exports.mochaGlobalTeardown = async function () {
await this.server.stop();
console.log('server stopped!');
};
…或 ES 模块
// fixtures.mjs, cont'd
// can be async or not
export async function mochaGlobalTeardown() {
await this.server.stop();
console.log('server stopped!');
}
您会注意到我们在夹具示例中使用了 this。全局设置夹具和全局拆卸夹具共享一个上下文,这意味着我们可以在设置夹具中向上下文对象(this)添加属性,并在拆卸夹具中稍后引用它们。当夹具在单独的文件中时,这更有用,因为您可以只使用 JS 的变量作用域规则(下面的示例)。
如 上面 所述 - 以及 下面 - 测试文件无法访问此上下文对象。
# 何时使用全局夹具
全局夹具适用于启动服务器、打开套接字或以其他方式创建您的测试将通过 I/O 重复访问的资源。
# 何时不使用全局夹具
如果您需要访问内存中的值(例如文件句柄或数据库连接),不要使用全局夹具来执行此操作,因为您的测试将无法访问该值。
您可以很聪明地尝试通过将某些内容分配给
global对象来解决此限制,但这在并行模式下不起作用。最好遵守规则!
相反,使用全局夹具来启动数据库,并使用 根钩子插件 或普通的 钩子 来创建连接。
以下是如何使用全局夹具和“全部之前”钩子来完成工作的示例。请注意,我们在测试中没有在任何地方引用 server 对象!
首先,使用全局夹具启动和停止测试服务器
// fixtures.mjs
let server;
export const mochaGlobalSetup = async () => {
server = await startSomeServer({port: process.env.TEST_PORT});
console.log(`server running on port ${server.port}`);
};
export const mochaGlobalTeardown = async () => {
await server.stop();
console.log('server stopped!');
};
然后,在您的测试中连接到服务器
// test.spec.mjs
import {connect} from 'my-server-connector-thingy';
describe('my API', function () {
let connection;
before(async function () {
connection = await connect({port: process.env.TEST_PORT});
});
it('should be a nice API', function () {
// assertions here
});
after(async function () {
return connection.close();
});
});
最后,使用此命令将它们整合在一起:mocha --require fixtures.mjs test.spec.mjs。
# 测试夹具决策树向导
此流程图将帮助您确定应该使用哪种 钩子、根钩子插件 或 全局夹具。
# 接口
Mocha 的“接口”系统允许开发人员选择他们的 DSL 样式。Mocha 具有 BDD、TDD、Exports、QUnit 和 Require 样式的接口。
# BDD
BDD 接口提供 describe()、context()、it()、specify()、before()、after()、beforeEach() 和 afterEach()。
context() 只是 describe() 的别名,并且行为相同;它提供了一种使测试更易于阅读和组织的方法。类似地,specify() 是 it() 的别名。
所有前面的示例都是使用 BDD 接口编写的。
describe('Array', function () {
before(function () {
// ...
});
describe('#indexOf()', function () {
context('when not present', function () {
it('should not throw an error', function () {
(function () {
[1, 2, 3].indexOf(4);
}).should.not.throw();
});
it('should return -1', function () {
[1, 2, 3].indexOf(4).should.equal(-1);
});
});
context('when present', function () {
it('should return the index where the element first appears in the array', function () {
[1, 2, 3].indexOf(3).should.equal(2);
});
});
});
});
# TDD
TDD 接口提供 suite()、test()、suiteSetup()、suiteTeardown()、setup() 和 teardown()
suite('Array', function () {
setup(function () {
// ...
});
suite('#indexOf()', function () {
test('should return -1 when not present', function () {
assert.equal(-1, [1, 2, 3].indexOf(4));
});
});
});
# Exports
Exports 接口与 Mocha 的前身 expresso 非常相似。键 before、after、beforeEach 和 afterEach 是特殊情况,对象值是套件,函数值是测试用例
module.exports = {
before: function () {
// ...
},
Array: {
'#indexOf()': {
'should return -1 when not present': function () {
[1, 2, 3].indexOf(4).should.equal(-1);
}
}
}
};
# QUnit
受 QUnit 启发的接口与 QUnit 的“扁平”外观相匹配,其中测试套件标题定义在测试用例之前。与 TDD 一样,它使用 suite() 和 test(),但类似于 BDD,它还包含 before()、after()、beforeEach() 和 afterEach()。
function ok(expr, msg) {
if (!expr) throw new Error(msg);
}
suite('Array');
test('#length', function () {
var arr = [1, 2, 3];
ok(arr.length == 3);
});
test('#indexOf()', function () {
var arr = [1, 2, 3];
ok(arr.indexOf(1) == 0);
ok(arr.indexOf(2) == 1);
ok(arr.indexOf(3) == 2);
});
suite('String');
test('#length', function () {
ok('foo'.length == 3);
});
# Require
require 接口允许您使用 require 直接要求 describe 和朋友词,并随意调用它们。如果您想避免在测试中使用全局变量,此接口也很有用。
注意:require 接口不能通过 node 可执行文件运行,必须通过 mocha 运行。
var testCase = require('mocha').describe;
var pre = require('mocha').before;
var assertions = require('mocha').it;
var assert = require('chai').assert;
testCase('Array', function () {
pre(function () {
// ...
});
testCase('#indexOf()', function () {
assertions('should return -1 when not present', function () {
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});
# 报告器
Mocha 报告器会适应终端窗口,并且当 stdio 流与 TTY 不相关联时始终禁用 ANSI 转义颜色。
# Spec
别名:Spec、spec
这是默认的报告器。Spec 报告器输出一个分层视图,嵌套方式与测试用例相同。

# 点矩阵
别名:Dot、dot
点矩阵报告器是一系列代表测试用例的字符。失败以红色感叹号(!)突出显示,待定测试以蓝色逗号(,)突出显示,慢速测试以黄色突出显示。如果您更喜欢最少的输出,则效果很好。
# Nyan
别名:Nyan、nyan
Nyan 报告器正是您所期望的

# TAP
别名:TAP、tap
TAP 报告器为 Test-Anything-Protocol 消费者发出行。

# 着陆带
别名:Landing、landing
着陆带报告器是一个花哨的测试报告器,模拟飞机着陆 😃 unicode ftw

# 列表
别名:List、list
列表报告器输出一个简单的规范列表,作为测试用例通过或失败,在输出底部输出失败详细信息。

# 进度
别名:Progress、progress
进度报告器实现了一个简单的进度条

# JSON
别名:JSON、json
JSON 报告器在测试完成后(无论失败与否)输出一个大型 JSON 对象。
默认情况下,它将输出到控制台。要直接写入文件,请使用 --reporter-option output=filename.json。

# JSON 流
别名:JSONStream、json-stream
JSON 流报告器在它们发生时输出换行符分隔的 JSON“事件”,从“开始”事件开始,然后是测试通过或失败,最后是最终的“结束”事件。

# Min
别名:Min、min
Min 报告器仅显示摘要,同时在失败时仍输出错误。此报告器与 --watch 配合使用效果很好,因为它会清除终端以将测试摘要保留在顶部。

# Doc
别名:Doc、doc
Doc 报告器输出测试的分层 HTML 主体表示。用标题、页脚和一些样式将其包装起来,然后您将获得一些很棒的文档!

例如,假设您有以下 JavaScript
describe('Array', function () {
describe('#indexOf()', function () {
it('should return -1 when the value is not present', function () {
[1, 2, 3].indexOf(5).should.equal(-1);
[1, 2, 3].indexOf(0).should.equal(-1);
});
});
});
命令 mocha --reporter doc array 将产生
<section class="suite">
<h1>Array</h1>
<dl>
<section class="suite">
<h1>#indexOf()</h1>
<dl>
<dt>should return -1 when the value is not present</dt>
<dd>
<pre><code>[1,2,3].indexOf(5).should.equal(-1);
[1,2,3].indexOf(0).should.equal(-1);</code></pre>
</dd>
</dl>
</section>
</dl>
</section>
SuperAgent 请求库的 测试文档 是使用 Mocha 的 doc 报告器使用此 Bash 命令生成的
$ mocha --reporter=doc | cat docs/head.html - docs/tail.html > docs/test.html
查看 SuperAgent 的 Makefile 以供参考。
# Markdown
别名:Markdown、markdown
Markdown 报告器为您的测试套件生成一个 Markdown TOC 和主体。如果您想在 Github wiki 页面中使用测试作为文档,或者在 Github 可以渲染的存储库中的 Markdown 文件中使用测试,这非常有用。例如,这是 Connect 的 测试输出。
# XUnit
别名:XUnit、xunit
XUnit 报告器也可用。它输出一个与 XUnit 兼容的 XML 文档,通常适用于 CI 服务器。
默认情况下,它将输出到控制台。要直接写入文件,请使用 --reporter-option output=filename.xml。
要指定自定义报告标题,请使用 --reporter-option suiteName="Custom name"。
# 第三方报告器
Mocha 允许您定义自定义报告器。有关更多信息,请参阅 wiki。
示例
- TeamCity 报告器
- 我们的 工作示例
# HTML 报告器
别名:HTML、html
HTML 报告器不适合在命令行中使用。
# Node.JS 原生 ESM 支持
v7.1.0 新功能
Mocha 现在支持将您的测试编写为 ES 模块,而不仅仅是使用 CommonJS。例如
// test.mjs
import {add} from './add.mjs';
import assert from 'assert';
it('should add to numbers from an es module', () => {
assert.equal(add(3, 5), 8);
});
要启用此功能,您无需执行任何特殊操作。将您的测试文件编写为 ES 模块。在 Node.js 中,这意味着将文件扩展名更改为 .mjs,或者如果您想使用常规的 .js 扩展名,则在您的 package.json 中添加 "type": "module"。更多信息可以在 Node.js 文档 中找到。
# 当前限制
- 监视模式 不支持 ES 模块测试文件
- 自定义报告器 和 自定义接口 只能是 CommonJS 文件
- 配置文件 只能是 CommonJS 文件 (
.mocharc.js或.mocharc.cjs) - 当使用像
proxyquire、rewiremock或rewire这样的库进行模块级模拟时,请不要使用 ES 模块作为您的测试文件。您可以切换到使用testdouble,它支持 ESM。
# 在浏览器中运行 Mocha
Mocha 在浏览器中运行。Mocha 的每个版本都会有新的 ./mocha.js 和 ./mocha.css 构建,供在浏览器中使用。
一个典型的设置可能如下所示,我们调用 mocha.setup('bdd') 来使用 BDD 接口,然后加载测试脚本,并在 onload 时使用 mocha.run() 运行它们。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Mocha Tests</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="https://unpkg.com/chai/chai.js"></script>
<script src="https://unpkg.com/mocha/mocha.js"></script>
<script class="mocha-init">
mocha.setup('bdd');
mocha.checkLeaks();
</script>
<script src="test.array.js"></script>
<script src="test.object.js"></script>
<script src="test.xhr.js"></script>
<script class="mocha-exec">
mocha.run();
</script>
</body>
</html>
# Grep
浏览器可以使用 --grep 作为功能。将查询字符串追加到您的 URL:?grep=api。
# 浏览器配置
Mocha 选项可以通过 mocha.setup() 设置。示例
// Use "tdd" interface. This is a shortcut to setting the interface;
// any other options must be passed via an object.
mocha.setup('tdd');
// This is equivalent to the above.
mocha.setup({
ui: 'tdd'
});
// Examples of options:
mocha.setup({
allowUncaught: true,
asyncOnly: true,
bail: true,
checkLeaks: true,
dryRun: true,
failZero: true,
forbidOnly: true,
forbidPending: true,
global: ['MyLib'],
retries: 3,
rootHooks: { beforeEach(done) { ... done();} },
slow: '100',
timeout: '2000',
ui: 'bdd'
});
# 浏览器特定选项
浏览器 Mocha 支持许多,但并非所有 cli 选项。要使用包含“ - ”的 cli 选项,请将选项转换为驼峰式命名法 (例如,check-leaks 转换为 checkLeaks)。
# 与 cli 选项 略有不同的选项
reporter {string|constructor} 您可以传递报告器的名称或自定义报告器的构造函数。您可以找到浏览器 此处 的 推荐 报告器。也可以使用 内置报告器。它们在浏览器中的使用既不推荐也不支持,请打开控制台查看测试结果。
# 仅在浏览器上下文中起作用的选项
noHighlighting {boolean} 如果设置为 true,则不要尝试在输出测试代码上使用语法高亮。
# 报告
在浏览器中运行 Mocha 时,HTML 报告器是默认报告器。它看起来像这样

Mochawesome 是默认 HTML 报告器的绝佳替代方案。
# 配置 Mocha (Node.js)
v6.0.0 中新增
Mocha 支持配置文件,这在现代命令行工具中很常见,并且支持多种格式
- JavaScript:在项目的根目录中创建一个
.mocharc.js(或在您的package.json中使用"type"="module"时创建一个.mocharc.cjs),并导出一个包含您的配置的对象 (module.exports = {/* ... */})。 - YAML:在项目的根目录中创建一个
.mocharc.yaml(或.mocharc.yml)。 - JSON:在项目的根目录中创建一个
.mocharc.json(或.mocharc.jsonc)。注释 - 虽然不是有效的 JSON - 在此文件中是允许的,并且会被 Mocha 忽略。 - package.json:在项目的
package.json中创建一个mocha属性。
# 自定义位置
您可以使用 --config <path> 选项指定配置文件的自定义位置。Mocha 将使用文件的扩展名来确定如何解析文件,如果未知,将假定为 JSON。
您也可以使用 --package <path> 选项指定自定义 package.json 位置。
# 忽略配置文件
要跳过查找配置文件,请使用 --no-config。同样,使用 --no-package 阻止 Mocha 在 package.json 中查找配置。
# 优先级
如果没有给出自定义路径,并且如果同一个目录中存在多个配置文件,Mocha 将只搜索并使用其中一个。优先级是
.mocharc.js.mocharc.yaml.mocharc.yml.mocharc.jsonc.mocharc.json
# 合并
Mocha 还会将 package.json 中找到的任何选项合并到其运行时配置中。如果发生冲突,优先级是
- 命令行上指定的参数
- 配置文件 (
.mocharc.js、.mocharc.yml等) package.json的mocha属性
可以安全重复的选项 (例如,--require) 将被连接,优先级更高的配置源将出现在列表的前面。例如,一个 .mocharc.json 包含 "require": "bar",再加上执行 mocha --require foo,会导致 Mocha 按顺序要求 foo,然后要求 bar。
# 扩展配置
配置可以使用 extends 关键字从其他模块继承。有关更多信息,请参见 此处。
# 配置格式
- 任何“布尔”标志 (不需要参数,例如
--bail) 都可以使用布尔值指定,例如:"bail": true。 - 任何“数组”类型选项 (有关列表,请参见
mocha --help) 都可以是单个字符串值。 - 对于包含破折号 (
-) 的选项,选项名称可以使用驼峰式命名法指定。 - 别名是有效的名称,例如,
R代替reporter。 - 测试文件可以使用
spec指定,例如,"spec": "test/**/*.spec.js"。 node的标志也支持在配置文件中使用。请谨慎使用,因为这些标志可能在不同版本的 Node.js 之间有所不同!
有关更多配置示例,请参见 GitHub 上的 example/config 目录。
# test/ 目录
默认情况下,mocha 查找 glob "./test/*.{js,cjs,mjs}",因此您可能希望将测试放在 test/ 文件夹中。如果您想包含子目录,请传递 --recursive 选项。
要配置 mocha 查找测试的位置,您可以传递自己的 glob
$ mocha --recursive "./spec/*.js"
一些 shell 支持使用 globstar (**) 通配符进行递归匹配。Bash >= 4.3 支持使用 globstar 选项,该选项 必须启用 才能获得与传递 --recursive 选项相同的结果 (ZSH 和 Fish 默认支持此功能)。启用递归匹配后,以下内容与传递 --recursive 相同
$ mocha "./spec/**/*.js"
您应该始终在 npm 脚本中引用您的 glob。如果您使用引号,node-glob 模块将处理其扩展。为了最大限度地兼容,请将整个表达式用双引号括起来,并在表达式中避免使用 $、"、^ 和 \。
请参见此 教程,了解如何使用 glob。
注意:建议将 glob 放在双引号中以确保可移植性。
# 错误代码
v6.0.0 中新增
当 Mocha 本身抛出异常时,关联的 Error 将具有 code 属性。在适用情况下,使用者应该检查 code 属性,而不是对 message 属性进行字符串匹配。下表描述了这些错误代码
| 代码 | 描述 |
|---|---|
ERR_MOCHA_INVALID_ARG_TYPE | 为给定参数传递了错误类型 |
ERR_MOCHA_INVALID_ARG_VALUE | 为给定参数传递了无效或不支持的值 |
ERR_MOCHA_INVALID_EXCEPTION | 抛出了一个虚假或未充分指定的异常 |
ERR_MOCHA_INVALID_INTERFACE | 选项中指定的接口未找到 |
ERR_MOCHA_INVALID_REPORTER | 选项中指定的报告器未找到 |
ERR_MOCHA_NO_FILES_MATCH_PATTERN | 找不到测试文件 |
ERR_MOCHA_UNSUPPORTED | 请求的行为、选项或参数不受支持 |
# 编辑器插件
以下与编辑器相关的软件包可用
# TextMate
Mocha TextMate 包 包含代码片段,可以使编写测试更快更愉快。
# JetBrains
JetBrains 为其 IDE 套件 (IntelliJ IDEA、WebStorm 等) 提供了一个 NodeJS 插件,其中包含 Mocha 测试运行器,以及其他功能。

该插件名为 NodeJS,可以通过 Preferences > Plugins 安装,前提是您的许可证允许这样做。
# Wallaby.js
Wallaby.js 是一种持续测试工具,它为 VS Code、Atom、JetBrains IDE (IntelliJ IDEA、WebStorm 等)、Sublime Text 和 Visual Studio 中的 Mocha 提供实时代码覆盖率,适用于浏览器和 node.js 项目。

# Emacs
通过第三方软件包 mocha.el 可以使用 Emacs 支持运行 Mocha 测试。该软件包在 MELPA 上可用,可以通过 M-x package-install mocha 安装。

# Mocha 侧边栏 (VS Code)
Mocha 侧边栏 是 VS Code 最完整的 mocha 扩展。
# 功能
- 在 VS Code 侧边栏菜单中查看所有测试
- 运行和调试从所有测试到单个测试 (以及每个套件) 的每个级别层次结构的测试
- 在文件保存时自动运行测试
- 直接在代码编辑器中查看测试结果

# 示例
真实的示例代码
# 测试 Mocha
要运行 Mocha 的测试,您需要 GNU Make 或兼容的工具;Cygwin 应该可以工作。
$ cd /path/to/mocha
$ npm install
$ npm test
# 更多信息
除了在 我们的 Discord 上与我们聊天之外,有关使用间谍、模拟和共享行为等更多信息,请务必查看 GitHub 上的 Mocha Wiki。有关 Mocha 的运行示例,请查看 example/tests.html。有关 JavaScript API,请查看 API 文档 或 源代码。