简单灵活趣味

Mocha 是一个功能丰富的 JavaScript 测试框架,可在 Node.js 和浏览器中运行,使异步测试变得简单有趣。 Mocha 测试按顺序运行,允许灵活且准确的报告,同时将未捕获的异常映射到正确的测试用例。 托管在 GitHub 上。

# 赞助商

在工作中使用 Mocha?询问您的经理或营销团队他们是否愿意帮助 支持 我们的项目。 您公司的徽标也将显示在 npmjs.com 和我们的 GitHub 存储库 上。

# 支持者

发现 Mocha 有用?成为 支持者 并通过每月捐款支持 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 步开始 下面

# 串行模式

  1. 用户(就是您)执行 mocha
  2. 加载来自配置文件的选项(如果存在)
  3. Mocha 处理提供的任何命令行选项(有关详细信息,请参阅有关 配置合并 的部分)
  4. 如果找到 node 可执行文件的已知标志
    1. Mocha 将在子进程中生成 node,并使用这些标志执行自身
    2. 否则,Mocha 不会生成子进程
  5. Mocha 加载由 --require 指定的模块
    1. 如果以这种方式加载的文件包含已知的 Mocha 特定导出(例如,根钩子插件),Mocha 将“注册”这些导出
    2. 如果不是,Mocha 将忽略 --require’d 模块的任何导出
  6. Mocha 验证通过 --require 或其他方式加载的任何自定义报告器或接口
  7. Mocha 发现测试文件;当没有给出文件或目录时,它会找到当前工作目录相对路径的 test 目录(但不包括其子目录)中的扩展名为 .js.mjs.cjs 的文件
  8. (默认)bdd 接口 以无特定顺序加载测试文件,这些文件被赋予特定于接口的 global 上下文(这就是例如 describe() 最终成为测试文件中的全局变量的方式)
    1. 当加载测试文件时,Mocha 会执行其所有套件并找到——但不会执行——其中的任何钩子和测试。
    2. 顶级钩子、测试和套件都是“不可见”根套件的成员;整个进程只有一个根套件
  9. Mocha 运行 全局设置夹具(如果有)
  10. 从“根”套件开始,Mocha 执行
  11. 任何“beforeAll”钩子(对于套件,这只会发生一次;请参阅 根钩子插件
  12. 对于每个测试,Mocha 执行
    1. 任何“beforeEach”钩子
    2. 测试(并报告结果)
    3. 任何“afterEach”钩子
  13. 如果当前套件有子套件,请对每个子套件重复步骤 10;每个子套件继承其父级中定义的任何“beforeEach”和“afterEach”钩子
  14. 任何“afterAll”钩子(对于套件,这只会发生一次;请参阅 根钩子插件
  15. Mocha 打印最终摘要/结语(如果适用)
  16. Mocha 运行 全局拆卸夹具(如果有)

# 并行模式

  1. 重复步骤 1 到 6,来自上面的 串行模式,跳过报告器验证
  2. 找到的所有测试文件都被放入队列中(它们不会被主进程加载)
  3. Mocha 运行 全局设置夹具(如果有)
  4. Mocha 创建一个子进程池(“工作者”)
  5. 工作者运行它接收的第一个测试之前,工作者通过以下方式“引导”自身
    1. 加载所有 --require’d 模块
    2. 注册任何根钩子插件
    3. 忽略全局夹具和自定义报告器
    4. 断言内置或自定义接口有效
  6. 当工作者收到要运行的测试文件时,工作者会为单个测试文件创建一个新的 Mocha 实例,并且
  7. 工作者重复步骤 8,来自上面的 步骤
  8. 工作者重复步骤 10,来自上面的 步骤,但工作者不会直接报告测试结果;它将它们保存在内存缓冲区中
  9. 当工作者完成测试文件时,缓冲的结果将返回到主进程,主进程然后将它们提供给用户指定的报告器(默认情况下为 spec
  10. 工作者使自身可用于池;如果还有剩余的测试文件,池会将另一个测试文件提供给工作者运行
  11. Mocha 打印最终摘要/结语(如果适用)
  12. 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,它将起作用! 这意味着您可以使用以下库

# 异步代码

通过向 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();
  }
});

这将跳过套件中的所有itbeforeEach/afterEachdescribe 块。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 报告器所示

test duration

测试持续时间有三个级别(如以下图像所示)

  1. 快速:在“慢”阈值的一半内运行的测试将以绿色显示持续时间(如果有的话)。
  2. 正常:超过阈值一半(但仍在阈值内)运行的测试将以黄色显示持续时间。
  3. 慢速:超过阈值运行的测试将以红色显示持续时间。

test duration range

要调整被视为“慢速”的内容,可以使用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 支持断言库中任何抛出的AssertionErrorerr.expectederr.actual 属性。Mocha 将尝试显示预期结果与断言实际看到的之间的差异。以下是如何使用--inline-diffs 显示“字符串”差异的示例

string 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 进程。这可能很耗时,因为问题并不总是很明显——但这样做是推荐的

为了确保您的测试没有留下混乱,以下是一些入门想法

# --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 现在是别名。

定义一个全局变量名。例如,假设您的应用程序故意公开名为appYUI 的全局变量,您可能想要添加--global app --global YUI

--global 接受通配符。您可以执行--global '*bar',它将匹配foobarbarbar 等。您也可以传递'*' 来忽略所有全局变量。

--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>

在加载用户界面或测试文件之前,需要一个模块。这对以下情况很有用

以这种方式需要的模块预计会同步执行;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

使用 --grepfgrep 指定的匹配的反向

需要 --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-optionnode 标志传递给 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.onlydescribe.onlythis.only() 等。 这是因为与上面提到的不兼容的报告器相同的原因:在并行模式下,Mocha 不会在运行测试之前将所有文件和套件加载到内存中。

建议的解决方法

  1. 改用 --grep--fgrep;它效率不高,但可以工作。
  2. 不要使用并行模式。很可能,您不会运行太多排他性测试,因此您不会从并行模式中获得很大的好处。

提示:如果您的配置文件中定义了并行模式,则可以通过使用 --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 中。

以下是一些建议的解决方法

  1. 在每个测试文件的顶部使用 require('./setup.js')import './setup.js'。最适合那些不喜欢样板代码的人。
  2. 推荐:使用新的(也是从 v8.0.0 开始的)根钩子插件 系统,在“必需”文件中定义根钩子。

如果您需要只运行一次代码,请改用 全局夹具

# 不支持浏览器

目前,并行模式仅在 Node.js 中可用。

# 第三方报告器的报告器 API 限制

第三方报告器在尝试访问 TestSuiteHook 对象中不存在的属性时可能会遇到问题。如果第三方报告器在并行模式下不起作用(但在串行模式下起作用),请 提交问题

# 并行模式故障排除

如果您发现您的测试在使用 --parallel 运行时无法正常工作,要么耸耸肩继续前进,要么使用此方便的清单来使事情正常工作

# 关于并行测试的注意事项

某些类型的测试太适合并行运行。例如,极其时间敏感的测试,或对有限资源池进行 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 映射到 beforeAllsetup 映射到 beforeEach

可用的根钩子及其行为

提示:如果您需要确保代码在任何模式下都只运行一次,请使用 全局夹具

与其他钩子一样,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.jshooks-b.js 中的根钩子,请使用 --require hooks-a.js --require hooks-b.js。这些将按顺序注册(并运行)。

# 迁移测试以使用根钩子插件

要将使用根钩子的测试迁移到根钩子插件

  1. 找到您的根钩子(在套件外部定义的钩子 - 通常是 describe() 回调)。
  2. 创建一个新文件,例如 test/hooks.js
  3. 移动您的根钩子到 test/hooks.js 中。
  4. test/hooks.js 中,将您的钩子设为导出的 mochaHooks 属性的成员。
  5. 在运行测试时使用 --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 变为 afterAllbefore 变为 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 一起使用)。

# 迁移库以使用根钩子插件

如果您是库维护者,并且您的库使用根钩子,您可以通过重构您的入口点来迁移

# 全局夹具

v8.2.0 中新增

乍一看,全局夹具似乎与 根钩子 类似。但是,与根钩子不同,全局夹具

  1. 保证仅执行一次
  2. 在并行模式、观察模式和串行模式下工作相同
  3. 不与测试、套件或其他钩子共享上下文

全局夹具分为两种类型:全局设置夹具全局拆卸夹具

# 全局设置夹具

要创建全局设置夹具,请从脚本中导出 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 Fixture WizardMy testsneed setup!Setup MUST runonce and only onceSetup MUST sharestate with testsYESUse Root Hooks andAvoid Parallel ModeUse Global FixturesShould setup affecttests across ALL files?Use Root HooksUse Plain HooksYESNONOYESNO

# 接口

Mocha 的“接口”系统允许开发人员选择他们的 DSL 样式。Mocha 具有 BDDTDDExportsQUnitRequire 样式的接口。

# 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 非常相似。键 beforeafterbeforeEachafterEach 是特殊情况,对象值是套件,函数值是测试用例

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

别名:Specspec

这是默认的报告器。Spec 报告器输出一个分层视图,嵌套方式与测试用例相同。

spec reporter spec reporter with failure

# 点矩阵

别名:Dotdot

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

dot matrix reporter

# Nyan

别名:Nyannyan

Nyan 报告器正是您所期望的

js nyan cat reporter

# TAP

别名:TAPtap

TAP 报告器为 Test-Anything-Protocol 消费者发出行。

test anything protocol

# 着陆带

别名:Landinglanding

着陆带报告器是一个花哨的测试报告器,模拟飞机着陆 😃 unicode ftw

landing strip plane reporter landing strip with failure

# 列表

别名:Listlist

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

list reporter

# 进度

别名:Progressprogress

进度报告器实现了一个简单的进度条

progress bar

# JSON

别名:JSONjson

JSON 报告器在测试完成后(无论失败与否)输出一个大型 JSON 对象。

默认情况下,它将输出到控制台。要直接写入文件,请使用 --reporter-option output=filename.json

json reporter

# JSON 流

别名:JSONStreamjson-stream

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

json stream reporter

# Min

别名:Minmin

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

min reporter

# Doc

别名:Docdoc

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

doc reporter

例如,假设您有以下 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

别名:Markdownmarkdown

Markdown 报告器为您的测试套件生成一个 Markdown TOC 和主体。如果您想在 Github wiki 页面中使用测试作为文档,或者在 Github 可以渲染的存储库中的 Markdown 文件中使用测试,这非常有用。例如,这是 Connect 的 测试输出

# XUnit

别名:XUnitxunit

XUnit 报告器也可用。它输出一个与 XUnit 兼容的 XML 文档,通常适用于 CI 服务器。

默认情况下,它将输出到控制台。要直接写入文件,请使用 --reporter-option output=filename.xml

要指定自定义报告标题,请使用 --reporter-option suiteName="Custom name"

# 第三方报告器

Mocha 允许您定义自定义报告器。有关更多信息,请参阅 wiki

示例

# HTML 报告器

别名:HTMLhtml

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 文档 中找到。

# 当前限制

# 在浏览器中运行 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 报告器是默认报告器。它看起来像这样

HTML test reporter

Mochawesome 是默认 HTML 报告器的绝佳替代方案。

# 配置 Mocha (Node.js)

v6.0.0 中新增

Mocha 支持配置文件,这在现代命令行工具中很常见,并且支持多种格式

# 自定义位置

您可以使用 --config <path> 选项指定配置文件的自定义位置。Mocha 将使用文件的扩展名来确定如何解析文件,如果未知,将假定为 JSON。

您也可以使用 --package <path> 选项指定自定义 package.json 位置。

# 忽略配置文件

要跳过查找配置文件,请使用 --no-config。同样,使用 --no-package 阻止 Mocha 在 package.json 中查找配置。

# 优先级

如果没有给出自定义路径,并且如果同一个目录中存在多个配置文件,Mocha 将只搜索并使用其中一个。优先级是

  1. .mocharc.js
  2. .mocharc.yaml
  3. .mocharc.yml
  4. .mocharc.jsonc
  5. .mocharc.json

# 合并

Mocha 还会将 package.json 中找到的任何选项合并到其运行时配置中。如果发生冲突,优先级是

  1. 命令行上指定的参数
  2. 配置文件 (.mocharc.js.mocharc.yml 等)
  3. package.jsonmocha 属性

可以安全重复的选项 (例如,--require) 将被连接,优先级更高的配置源将出现在列表的前面。例如,一个 .mocharc.json 包含 "require": "bar",再加上执行 mocha --require foo,会导致 Mocha 按顺序要求 foo,然后要求 bar

# 扩展配置

配置可以使用 extends 关键字从其他模块继承。有关更多信息,请参见 此处

# 配置格式

有关更多配置示例,请参见 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 选项相同的结果 (ZSHFish 默认支持此功能)。启用递归匹配后,以下内容与传递 --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 测试运行器,以及其他功能。

JetBrains Mocha Runner Plugin in Action

该插件名为 NodeJS,可以通过 Preferences > Plugins 安装,前提是您的许可证允许这样做。

# Wallaby.js

Wallaby.js 是一种持续测试工具,它为 VS Code、Atom、JetBrains IDE (IntelliJ IDEA、WebStorm 等)、Sublime Text 和 Visual Studio 中的 Mocha 提供实时代码覆盖率,适用于浏览器和 node.js 项目。

Wallaby.js in Action

# Emacs

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

Emacs Mocha Runner in Action

# Mocha 侧边栏 (VS Code)

Mocha 侧边栏 是 VS Code 最完整的 mocha 扩展。

# 功能

mocha side bar in Action

# 示例

真实的示例代码

# 测试 Mocha

要运行 Mocha 的测试,您需要 GNU Make 或兼容的工具;Cygwin 应该可以工作。

$ cd /path/to/mocha
$ npm install
$ npm test

# 更多信息

除了在 我们的 Discord 上与我们聊天之外,有关使用间谍、模拟和共享行为等更多信息,请务必查看 GitHub 上的 Mocha Wiki。有关 Mocha 的运行示例,请查看 example/tests.html。有关 JavaScript API,请查看 API 文档源代码

Matomo logo