简单灵活趣味

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 Wizard - Mocha 中文My 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