簡單彈性有趣

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. 任何「全部之前」掛鉤(對於套件,這只會發生一次;請參閱根掛鉤外掛程式
  12. 對於每個測試,Mocha 會執行
    1. 任何「每個之前」掛鉤
    2. 測試(並報告結果)
    3. 任何「每個之後」掛鉤
  13. 如果目前的套件有子套件,請對每個子套件重複步驟 10。;每個子套件繼承其父項定義的任何「每個之前」和「每個之後」掛鉤
  14. 任何「全部之後」掛鉤(對於套件,這只會發生一次;請參閱根掛鉤外掛程式
  15. Mocha 會列印最後摘要/尾聲(如果適用)
  16. Mocha 會執行全域清除固定裝置(如果有)

#平行模式

  1. 重複步驟 1 至 6,從序列模式跳過報告員驗證
  2. 找到的所有測試檔案都會放入佇列中(它們不會由主程序載入)
  3. Mocha 會執行全域設定固定裝置(如果有)
  4. Mocha 會建立一個子程序池(「工作人員」)
  5. 工作人員執行收到的第一個測試之前,工作人員會透過下列方式「自行開機」
    1. 載入所有--require的模組
    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,它就會運作!這表示您可以使用函式庫,例如

# 非同步程式碼

透過將一個參數(通常命名為 done)加入 it() 到一個測試回呼,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 來進行流暢的承諾斷言。

在 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);
});

上述測試會失敗,並顯示 錯誤:解析方法過於具體。指定一個回呼 *或* 傳回一個 Promise;不可同時指定。。在 v3.0.0 以前的版本中,呼叫 done() 會被有效忽略。

# 使用非同步 / 等待

如果您的 JS 環境支援 非同步 / 等待,您也可以像這樣撰寫非同步測試

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 會讓重構變得更困難!

# 掛鉤

Mocha 提供了「BDD」樣式介面,其中包含掛鉤 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 預提交掛鉤中)使用選項 --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()

若要以這種方式跳過多個測試,請在「全部之前」掛勾中使用 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 中更新:禁止在「全部之後」掛勾中跳過測試,否則會擲回例外。請使用回傳陳述式或其他方式來中止掛勾執行。

在 Mocha v3.0.0 之前,非同步測試和掛勾不支援 this.skip()

# 重試測試

您可以選擇重試失敗的測試,最多到某個次數。此功能旨在處理端到端測試(功能測試/Selenium…),其中資源無法輕易地模擬/存根。不建議將此功能用於單元測試

此功能會重新執行失敗的測試及其對應的 beforeEach/afterEach 掛勾,但不會重新執行 before/after 掛勾。this.retries() 對失敗的掛勾沒有影響。

注意:以下範例是使用 Selenium webdriver 編寫的(它 覆寫了針對 Promise 鏈的全球 Mocha 掛勾)。

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}));
});

使用 頂層 await,您可以在測試檔案載入時以動態且非同步的方式收集測試資料。
另請參閱 --delay,以取得不含 頂層 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.dev.org.tw/

# --allow-uncaught

預設情況下,Mocha 會嘗試捕捉執行測試時拋出的未捕捉例外,並將其報告為測試失敗。使用 --allow-uncaught 來停用此行為,並允許未捕捉例外傳播。通常會導致程序崩潰。

此旗標在除錯特別難追蹤的例外時很有用。

# --async-only, -A

強制執行測試必須以「非同步」樣式編寫的規則,表示每個測試提供 done 回呼或傳回 Promise。不符合規定的測試將標記為失敗。

# --bail, -b

導致 Mocha 在遇到第一個測試失敗後停止執行測試。對應的「每個之後」和「全部之後」掛勾會執行潛在的清理。

--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 中更新。

簡而言之:如果你的測試在升級到 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 在遇到略過的(“pending”)測試或套件時失敗,並中止進一步的測試執行。

# --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 中的更新:使用檢查旗標呼叫 Mocha 時,會暗示 --timeout 0。不再需要 --timeout 99999999

指定測試案例逾時時間,預設為兩 (2) 秒 (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 自己的差異輸出。

某些斷言函式庫會提供自己的差異,這種情況下,無論預設值為何,都不會使用 Mocha 的差異。

Mocha 自己的差異輸出不符合任何已知的標準,且設計為人類可讀。

v9.2.1 中的新增功能

預設情況下,字串會在產生差異前被截斷為 8192 個字元。這是為了防止大型字串出現效能問題。

不過,在比較大型字串時,可能會讓輸出更難以解讀。因此,可以使用 --reporter-option maxDiffSize=[number] 來設定此值。

值 0 表示沒有限制,預設為 8192 個字元。

# --full-trace

啟用「完整」堆疊追蹤。預設情況下,Mocha 會嘗試將堆疊追蹤精簡為較不雜亂(但仍然有用)的輸出。

在除錯 Mocha 或 Node.js 本身中可疑的問題時,此標記很有用。

# --inline-diffs

啟用「內嵌」差異,這是用於區分字串的替代輸出。

在處理大型字串時很有用。

如果斷言函式庫提供自己的差異輸出,則不會執行任何動作。

# --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 <路徑>

已在 v8.0.0 中移除。請改用 設定檔

# --package <路徑>

v6.0.0 中的新增功能

指定 package.json 檔案 的明確路徑(表面上包含 mocha 屬性中的設定)。

預設情況下,Mocha 會在目前工作目錄或最近的祖先中尋找 package.json,並使用找到的第一個檔案(無論是否包含 mocha 屬性);若要略過 package.json 查詢,請使用 --no-package

# --extension <副檔名>

具有此副檔名的檔案將被視為測試檔案。預設為 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 <檔案|目錄|glob>

警告:--file平行模式 不相容。

明確包含要在其他測試檔案之前載入的測試檔案。允許多次使用 --file,並將按給定的順序載入。

如果您想宣告掛鉤在所有其他測試檔案中的每個測試之前執行,這會很有用。

以這種方式指定的文件不受 --sort--recursive 影響。

以這種方式指定的檔案應包含一個或多個套件、測試或掛鉤。如果不是這種情況,請改用 --require

# --ignore <檔案|目錄|glob>, --exclude <檔案|目錄|glob>,

明確忽略一個或多個測試檔案、目錄或 glob(例如,some/**/files*),否則這些檔案、目錄或 glob 會被載入。
可以多次指定。

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 Dev Tools 使用。

使用 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(或 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 中可用。

# 第三方報告器的 Reporter API 受限

第三方報告器在嘗試存取 TestSuiteHook 物件中不存在的屬性時,可能會遇到問題。如果第三方報告器無法在平行模式中運作(但在序列模式中可以運作),請 提交問題

# 平行模式疑難排解

如果你發現使用 --parallel 執行測試時,測試無法正常運作,你可以聳聳肩繼續,或使用這個方便的檢查清單讓一切正常運作

# 平行測試注意事項

某些類型的測試適合平行執行。例如,極度時間敏感的測試,或對有限資源池發出 I/O 要求的測試(例如開啟埠,或自動化瀏覽器視窗、存取測試資料庫或遠端伺服器等)。

免費層級的雲端 CI 服務可能無法為其建置代理程式提供合適的多核心容器或 VM。關於 CI 中預期的效能提升:你的實際情況可能有所不同。在 .mocharc.js 中使用條件判斷式檢查 process.env.CI,並適當地調整工作計數,可能會有幫助。

大於可用 CPU 核心數的 工作計數 不太可能(但並非不可能)看到效能提升。話雖如此,調整工作計數——沒有放諸四海皆準的解決方案,而你測試的獨特特性將決定最佳的工作計數;甚至可能更少的工作計數會更快!

# 平行模式工作人員 ID

v9.2.0 新功能

平行模式啟動的每個程序都會分配一個唯一 ID,從 0(第一個要啟動的程序)到 N-1(第 N 個程序)。可以在測試中透過環境變數 MOCHA_WORKER_ID 存取這個工作 ID。例如,可以用來為每個測試程序指定不同的資料庫、服務埠等。

# Root Hook 外掛程式

v8.0.0 新功能

在某些情況下,您可能希望在每個檔案的每個測試之前(或之後)使用 hook。這些稱為「root hook」。在 v8.0.0 之前,完成此操作的方法是將 --file 與 root hook 結合使用(請參閱 上述範例)。這在 v8.0.0 中仍然有效,但在平行模式下執行測試時不適用!因此,強烈建議不要使用此方法執行 root hook,否則未來可能會被棄用。

Root Hook 外掛程式 是透過 --require 載入的 JavaScript 檔案,用於「註冊」一個或多個 root hook,以便在所有測試檔案中使用。

在瀏覽器中,您可以透過 rootHooks 物件直接設定 root hook:mocha.setup({ rootHooks: {beforeEach() {...}} }),請參閱 mocha.setup()

# 定義 Root Hook 外掛程式

Root Hook 外掛程式檔案是一個透過 module.exports 匯出 mochaHooks 屬性的指令碼。它是透過 --require <file> 載入的。

以下是一個簡單的範例,說明如何定義 root hook,使用 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 語法。

# 可用的 Root Hook

Root hook 可與任何介面搭配使用,但屬性名稱不變。換句話說,如果您使用 tdd 介面,suiteSetup 會對應到 beforeAll,而 setup 會對應到 beforeEach

可用的 root hook 及其行為

提示:如果您需要確保程式碼在任何模式中只執行一次,請使用全域固定裝置

與其他掛鉤一樣,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 會變成 afterAll,而 before 會變成 beforeAll

您原本的 test/test.spec.js 現在應包含

// test/test.spec.js

describe('my test suite', function () {
  it('should have run my global setup', function () {
    // make assertion
  });
});

執行 mocha --require test/hooks.js test/test.spec.js 將會像以前一樣執行(現在已準備好與 --parallel 搭配使用)。

# 將函式庫遷移為使用 Root Hook 外掛程式

如果您是函式庫維護者,而且您的函式庫使用 root hook,您可以透過重構您的進入點來進行遷移

# 全域固定裝置

v8.2.0 中的新功能

乍看之下,全域固定裝置類似於 root hook。但是,與 root hook 不同,全域固定裝置

  1. 保證執行一次且僅一次
  2. 在平行模式、監控模式和序列模式中以相同方式運作
  3. 不與測試、組或其他 hook 共用內容

有兩種全域固定裝置:全域設定固定裝置全域清除固定裝置

# 全域設定固定裝置

若要建立全域設定固定裝置,請從指令碼匯出 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 的變數範圍規則(以下範例)。

上方下方 所述,測試檔案無法存取此內容物件。

# 何時使用全域固定裝置

全域固定裝置適用於啟動伺服器、開啟 socket 或建立其他資源,讓您的測試會透過 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 的前身 expressobeforeafterbeforeEachafterEach 鍵是特殊情況,物件值是套件,而函式值是測試案例

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

# Dot Matrix

別名:Dotdot

Dot Matrix 報告器是一系列代表測試案例的字元。失敗會以紅色驚嘆號 (!) 醒目顯示,未決測試以藍色逗號 (,) 顯示,而慢速測試則以黃色顯示。如果您偏好最少輸出,這是個不錯的選擇。

dot matrix reporter

# Nyan

別名:Nyannyan

Nyan 報告器正是您所預期的

js nyan cat reporter

# TAP

別名:TAPtap

TAP 報告器會為 Test-Anything-Protocol 使用者發出多行訊息。

test anything protocol

# Landing Strip

別名:Landinglanding

Landing Strip 報告器是一個模擬飛機降落的噱頭測試報告器 😃 unicode 真棒

landing strip plane reporter landing strip with failure

# 清單

別名:Listlist

List 報告器會在測試通過或失敗時輸出一個簡單的規格清單,並在輸出的底部輸出失敗的詳細資料。

list reporter

# 進度

別名:Progressprogress

Progress 報告器會實作一個簡單的進度條

progress bar

# JSON

別名:JSONjson

JSON 報告器會在測試完成時(無論是否失敗)輸出一個大型的 JSON 物件。

預設情況下,它會輸出到主控台。若要直接寫入檔案,請使用 --reporter-option output=filename.json

json reporter

# JSON 串流

別名:JSONStreamjson-stream

JSON 串流報告器會在事件發生時輸出以換行符號分隔的 JSON「事件」,從「開始」事件開始,接著是測試通過或失敗,最後是「結束」事件。

json stream reporter

# 最小

別名:Minmin

Min 報告器只會顯示摘要,但仍會在失敗時輸出錯誤。此報告器與 --watch 搭配使用效果極佳,因為它會清除終端機,讓您的測試摘要保持在最上方。

min reporter

# 文件

別名: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 目錄和主體。如果您想在 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 副檔名,請將 "type": "module" 新增到您的 package.json。您可以在 Node.js 文件 中找到更多資訊。

# 目前限制

# 在瀏覽器中執行 Mocha

Mocha 在瀏覽器中執行。Mocha 的每個版本都會有新的 ./mocha.js./mocha.css 建置,供瀏覽器使用。

一個典型的設定看起來可能像以下範例,我們在載入測試腳本之前呼叫 mocha.setup('bdd') 來使用 BDD 介面,並使用 mocha.run()onload 中執行它們。

<!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 支援許多,但並非所有 命令列選項。若要使用包含「-」的 命令列選項,請將選項轉換為駝峰式大小寫,(例如 check-leaks 轉換為 checkLeaks)。

#命令列選項 略有不同的選項

reporter {字串|建構函式} 您可以在此傳遞報表名稱或自訂報表的建構函式。您可以在 這裡 找到瀏覽器建議的報表。也可以使用 內建報表。不建議在瀏覽器中使用它們,也不支援它們,開啟主控台以查看測試結果。

# 在瀏覽器內容中運作的選項

noHighlighting {布林值} 如果設定為 true,請勿嘗試對輸出測試程式碼使用語法突顯。

# 報告

在瀏覽器中執行 Mocha 時,HTML 報表是預設的報表。它看起來像這樣

HTML test reporter

Mochawesome 是預設 HTML 報表的絕佳替代方案。

# 設定 Mocha (Node.js)

v6.0.0 中的新增功能

Mocha 支援設定檔,這是多種格式的現代命令列工具的典型設定

# 自訂位置

您可以使用 --config <路徑> 選項為您的設定檔指定自訂位置。Mocha 會使用檔案的副檔名來決定如何剖析檔案,如果未知,則會假設為 JSON。

您也可以使用 --package <路徑> 選項指定自訂 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) 將會串接,優先順序較高的設定來源會出現在清單中較前面。例如,包含 "require": "bar".mocharc.json,加上執行 mocha --require foo,將會讓 Mocha 依序載入 foobar

# 擴充設定

設定可以使用 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,可透過偏好設定 > 外掛程式進行安裝,假設您的授權允許。

# Wallaby.js

Wallaby.js 是一種持續測試工具,可在 VS Code、Atom、JetBrains IDE(IntelliJ IDEA、WebStorm 等)、Sublime Text 和 Visual Studio 中,為任何斷言函式庫提供 Mocha 的即時程式碼涵蓋率,適用於瀏覽器和 node.js 專案。

Wallaby.js in Action

# Emacs

Emacs 支援執行 Mocha 測試,可透過第三方套件 mocha.el 取得。此套件可在 MELPA 取得,並可透過 M-x package-install mocha 進行安裝。

Emacs Mocha Runner in Action

# Mocha Sidebar(VS Code)

Mocha Sidebar 是最完整的 Mocha 外掛程式,適用於 VS Code。

# 功能

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