簡單彈性有趣

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 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 的前身 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