[譯] 快速,完整的 Mocha 測試指南

collin發表於2019-10-15

瞭解如何使用 Mocha 為 JavaScript 應用程式編寫和執行測試

每個軟體開發人員都應該學習構建可預測、不易出錯且更具有彈性的軟體。測試驅動開發(TDD)是可以實現這一目標的主要方法之一。簡單的說,測試驅動的開發通常需要:

  1. 為所需要的功能編寫測試
  2. 執行測試
  3. 實現軟體功能
  4. 修復 bug 並重構直到所有測試透過
  5. 重複該週期以獲取新功能

與其它程式語言一樣,JavaScript 具有多種工具和框架,這些工具和框架可以在 Node.js 以及瀏覽器中進行測試驅動開發,例如:Jest, Jasmine, Mocha, QUnit, Karma, Cypress 等。

在本文中,您將快速而全面的瞭解如何使用 Mocha 來測試用 JavaScript 編寫的軟體功能。您將學習如何編寫自己的測試套件以及如何使用 Mocha 執行測試。

Mocha 入門

Mocha 是一個 JavaScript 測試執行程式,它可以在 Node.js 和瀏覽器中執行。它提供了透過非常簡單且相似的介面測試同步程式碼和非同步程式碼的功能。在繼續之前,您需要在本地計算機上全域性安裝 Mocha,或者作為專案的依賴項安裝 Mocha。這裡是使用 Node 包管理器(NPM)安裝的方法:

全域性安裝:

npm i --global mocha

作為開發依賴安裝到專案中:

npm i --save-dev mocha

在本地計算機上全域性安裝 mocha 可以使 mocha CLI 二進位制可在命令列終端中使用。因此,您可以使用 Mocha 在終端上執行測試,如下所示:

mocha

但是,如果僅將 Mocha 安裝為專案的開發依賴項,則可以從專案的 node_modules 目錄訪問 mocha 二進位制檔案,如下所示:

./node_modules/mocha/bin/mocha

要完成 Mocha 設定,您必須編寫具有非常簡單功能的單元測試,並配置指令碼以使用 Mocha 執行測試。

Mocha 會自動在專案的 test 目錄中查詢測試。因此,你必須先在專案根目錄中建立這個目錄。

mkdir test

接下來,修改 package.json 檔案中的 test 指令碼來使用 Mocha 執行測試,它應該是這樣的:

/* package.json */
{
    "scripts": {
        "test": "mocha"
    }
}

透過此設定,你可以非常簡單的使用下面的命令在專案中執行測試:

npm test

編寫測試

到現在為止,您已經透過 Mocha 執行測試做好了一切準備,但還沒有任何測試可以執行。下一步將是編寫針對軟體所需功能的測試。

斷言庫

編寫測試通常需要使用斷言庫。Mocha 不會區分您選擇使用的任何斷言庫。如果您在 Node.js 環境中使用 Mocha,你可以使用內建的 assert 模組作為您的斷言庫。但是,您可以使用更廣泛的斷言庫,例如 Chai, Expect.js, Should.js

對於本指南中所有測試,將使用 Chai 作為斷言庫。繼續安裝 Chai 作為您專案的依賴項,如下所示:

npm i --save-dev chai

Chai 提供如下斷言樣式:

  1. Assert 樣式
    
    var assert = require('chai').assert;
    var numbers = [1, 2, 3, 4, 5];

assert.isArray(numbers, 'is array of numbers');
assert.include(numbers, 2, 'array contains 2');
assert.lengthOf(numbers, 5, 'array contains 5 numbers');


2. Expect 樣式
```javascript
var expect = require('chai').expect;
var numbers = [1, 2, 3, 4, 5];

expect(numbers).to.be.an('array').that.includes(2);
expect(numbers).to.have.lengthOf(5);
  1. Should 樣式
    
    var should = require('chai').should();
    var numbers = [1, 2, 3, 4, 5];

numbers.should.be.an('array').that.includes(2);
numbers.should.have.lengthOf(5);


您可以從本文件中瞭解有關 [Chai](https://www.chaijs.com/api/assert/) 提供的斷言和斷言樣式的更多資訊。

### Mocha 介面

Mocha 提供了多種介面來定義測試套件,hooks 和單個測試,即:`BDD`, `TDD`, `Exports`, `QUnit` 和 `Require`。

在本文中,將使用 BDD 風格來定義和編寫測試,你可以在[本文件](https://mochajs.org/#interfaces)中檢查可用的 Mocha 樣式介面之間的比較。

使用 BDD 介面定義的測試套件如下所示:

```javascript
// 開始一個或多個測試套件
describe('#sum()', function() {
    // 新增一個測試 hook
    beforeEach(function() {
        // ... 每次測試前執行的一些邏輯
    })

    // 測試功能
    it('should add numbers', function() {
        // 新增一個斷言
        expect(sum(1, 2, 3, 4, 5)).to.equal(15);
    })

    // ... 更多測試
})

編寫你的第一個測試套件

是時候使用 Mocha 編寫並執行您的第一個測試套件了。下面是要實現的軟體需求。

一個具有以下行為的 sum() 函式:

  1. 可以接收任意數量的引數
  2. 要求所有引數均為數字,如果不是數字則丟擲錯誤
  3. 假設所有引數均為數字,則計算並返回所有引數的總和
  4. 如果未傳遞引數,則返回 0

根據最佳實踐,首先使用所需功能的測試定義測試套件。

在 test 目錄中新增一個 sum.js 並將下面程式碼片段新增到該檔案中:

/* test/sum.js */

var sum = require('../sum');
var expect = require('chai').expect;

describe('#sum', function () {
    context('whitout arguments', function () {
        it('should return 0', function () {
            expect(sum()).to.equal(0);
        })
    })

    context('with number arguments', function () {
        it('should return sum of arguments', function () {
            expect(sum(1, 2, 3, 4, 5)).to.equal(15);
        })

        it('should return argument when only one argument is passed', function() {
            expect(sum(5)).to.equal(5);
        })
    })

    context('with non-number arguments', function() {
        it('should throw error', function() {
            expect(function() {
                sum(1, 2, '3', [4], 5)
            }).to.throw(TypeError, 'sum() expects only numbers.');
        })
    })
})

請注意,儘管尚未建立 sum 模組,但測試檔案中仍需要該模組。還需要注意,sum() 呼叫包裝在函式中,以測試傳遞非數字引數時是否引發錯誤。這是 Chai 斷言庫中對 .throw() 斷言的要求。

接下來,實現 sum() 函式的功能,執行測試以確保所有測試都透過。

在專案的根目錄中建立 sum.js 檔案,幷包含下面程式碼:

module.exports = function () {
    // 將引數物件轉換成陣列
    var args = Array.prototype.slice.call(arguments);

    // 如果引數陣列中包含非數字引數,丟擲 TypeError 錯誤
    if (!args.every(Number.isFinite)) {
        throw new TypeError('sum() expects only numbers.');
    }

    // 返回所有引數的和
    return args.reduce(function (a, b) {
        return a + b;
    }, 0);
}

您現在可以透過前面定義的 test 指令碼在終端中執行測試:

npm test

你可以得到如下所示的輸出:

測試非同步程式碼

到目前為止,您編寫的測試都是針對同步程式碼的。然而,大多數 Node.js 應用程式需要大量的非同步程式碼。Mocha 還可以使用非常相似的程式碼輕鬆測試非同步程式碼。以下任何一種程式碼都可用於透過 Mocha 測試非同步程式碼:

  1. 使用回撥方法
  2. 使用 Promise(用於支援 Promise 的環境)
  3. 使用 async / await(用於支援非同步 function 的環境)

1. 使用回撥方法

it() 函式的第二個引數中的函式支援一個可選的引數作為回撥函式,如果傳遞了回撥函式,Mocha 知道該測試是針對非同步功能的。按照慣例,這個回撥函式稱為 done,但您可以自由使用任何識別符號。

it('test expectation', function(done) {
    // 測試非同步程式碼
    // 呼叫 done() 終止測試並繼續下一個測試
})

關於 done 回撥,需要注意以下幾點:

  1. 必須呼叫 done() 回撥以使 Mocha 終止測試並繼續進行下一個測試,否則測試將一直執行直到超時。
  2. it() 中,done() 不能被多次呼叫。多次呼叫將引發錯誤。
  3. done() 回撥是 Node 樣式的回撥,因此可以將 Error 例項(err) 作為其第一個引數。
  4. 使用 Error 例項呼叫 done() 回撥將導致測試失敗,並顯示給定錯誤。

在繼續之前,這是一個簡單的模組,這個模組匯出一個非同步 md5() 函式以計算字串的 MD5 值。

在專案根目錄中新增一個新檔名為 md5.js,並新增以下程式碼:

module.exports = function (string, callback) {
    var withCallback = typeof callback === 'function';

    try {
        var hash = crypto.createHash('md5')
            .update(string)
            .digest('hex');

        withCallback && callback(null, hash);
    } catch (e) {
        if (withCallback) {
            callback(e);
        } else {
            throw e;
        }
    }
}

以下程式碼片段使用回撥函式對非同步函式進行了簡單測試。

在專案的 test 目錄中建立一個新的 md5.js 檔案,並向其中新增以下內容:

/* test/md5.js */

var md5 = require('../md5');
var expect = require('chai').expect;

describe('#md5()', function() {
    context('with string argument', function() {
        it('should compute MD5 hash', function(done) {
            md5('Glad Chinda', function(err, hash) {
                // 使用 error 來呼叫 done() 回撥函式,
                // 來終止帶有錯誤的測試
                if (err) return done(err);

                // 新增以下斷言
                expect(hash)
                    .to.be.a('string')
                    .that.matches(/^[a-f0-9]{32}$/)
                    .and.equal('877dbb93f50eb8a89012e15bd37ee7e4');

                // 呼叫 done() 回撥函式來終止測試
                done();
            })
        })
    })

    context('with non-string argument', function() {
        it('should throw an error', function(done) {
            md5(12345, function(err, hash) {
                // 使用錯誤呼叫 done() 回撥來終止測試
                if (err) {
                    expect(function() { throw err })
                        .to.throw(TypeError, 'The "data" argument must be one of type string, TypedArray, or DataView. Received type number');

                    // 最後呼叫 done() 回撥來終止測試並返回
                    return done();
                }

                // 呼叫 done() 回撥來終止測試
                done();
            })
        })
    })
})

如果你在終端中執行測試,可以得到類似於以下內容的輸出:

2. 使用 Promise

如果您在支援 Promise 的環境中進行開發,則大多數非同步操作可能會基於 Promise。Mocha 還使您可以測試使用 Promise 的非同步程式碼。

每當您從傳遞給 it() 的函式中返回一個 Promise 時,Mocha 就會知道要測試的功能時非同步的,因此它會在繼續下一個測試之前等待實現 Promise。

從 Mocha V3.0.0 以及更高版本開始,在返回 promise 時呼叫 done() 回撥將導致異常,因此不允許這樣做。但是在舊版本的 Mocha 中,該呼叫將被忽略。

為了測試使用 promise 的非同步程式碼,您將建立基於 Promise 的 md5 的另一個版本。

在專案根目錄中建立一個新的檔案 promise-md5.js 並新增下面程式碼:

/* promise-md5.js */
const md5 = require('./md5');

module.exports = (string) => new Promise(
    (resolve, reject) => {
        md5(string, (err, hash) => {
            return err ? reject(err) : resolve(hash);
        })
    }
)

以下程式碼段包含一個用於 promise-md5 模組的簡單測試套件。在 test 目錄中建立一個 promise-md5.js 檔案並新增以下內容:

/* test/promise-md5.js */

var promiseMd5 = require('../promise-md5');
var expect = require('chai').expect;

describe('#promiseMd5()', function () {
    context('with string argument', function () {
        it('should compute MD5 hash', function () {
            return promiseMd5('Glad Chinda')
                .then(function (hash) {
                    // 新增一些斷言
                    expect(hash)
                        .to.be.a('string')
                        .that.matches(/^[a-f0-9]{32}$/)
                        .and.equal('877dbb93f50eb8a89012e15bd37ee7e4');
                })
        })
    })

    context('with non-string argument', function () {
        it('should throw an error', function () {
            return promiseMd5(12345)
                .catch(function (err) {
                    expect(function () { throw err })
                        .to.throw(TypeError, 'The "data" argument must be one of type string, TypedArray, or DataView. Received type number');
                })
        })
    })
})

現在,繼續使用此稍微修改的測試命令執行測試:

npm test -- -f promiseMd5

此命令使用 -- 將命令選項和引數傳遞到基礎的 Mocha CLI 二進位制檔案。-f 標誌指示 mocha 僅執行包含給定字串的測試,在這種情況下,該測試為 promiseMd5。

輸出如下所示:

3. 使用 async / await

對於支援最新 async / await 語法的環境,Mocha 還支援將非同步函式作為第二個引數傳遞給 it()。因此,以前的 promise-md5.js 測試可以重寫如下:

/* test/promise-md5.js */

var promiseMd5 = require('../promise-md5');
var expect = require('chai').expect;

describe('#promiseMd5()', function () {
    context('with string argument', function () {
        it('should compute MD5 hash', async function () {
            // 使用 await 等到 Promise 實現
            var hash = await promiseMd5('Glad Chinda');

            // 新增一些斷言
            expect(hash)
                .to.be.a('string')
                .that.match(/^[a-z0-9]{32}$/)
                .and.equal('877dbb93f50eb8a89012e15bd37ee7e4');
        })
    })

    context('with non-string argument', function() {
        it('should throw an error', async function() {
            await promiseMd5(12345).catch(function(err) {
                // 新增一個斷言以檢查錯誤
                expect(function() { throw err })
                    .to.throw(TypeError, 'The "data" argument must be one of type string, TypedArray, or DataView. Received type number');
            })
        })
    })
})

利用測試 hooks

Mocha 提供了建立測試 hooks 的功能,hooks 基本上是配置為在測試之前或之後執行的邏輯。它們對於設定測試的前提條件或者在測試後清理資源很有用。使用預設的 BDD 介面,Mocha 提供了四個hooks:

  1. before() - 在塊中的第一個測試用例之前執行一次
  2. beforeEach() - 在每個測試用例前執行
  3. afterEach() - 在每個測試用例之後執行
  4. after() - 在塊中的最後一個測試用例之後執行一次

根據適用於給定測試套件的 hooks,hooks 將按確定的順序與套件中的測試一起執行,如下所示:

before() -> beforeEach() -> test() -> afterEach() -> after()

建立 hooks

每個掛鉤基本上都將回撥引數作為引數。回撥函式包含觸發 hooks 時要執行的邏輯。就像常規測試用例一樣,邏輯可以是同步的也可以說非同步的。

describe('some module', function() {
    beforeEach(function() {
        // 每次測試之前執行的一些邏輯
        // 邏輯可以是同步的,也可以是非同步的
    })
})

hooks 也可以將可選描述作為第一個引數,這使得跟蹤錯誤更加容易。但是,如果將命名函式作為引數傳遞給 hooks,如果未傳遞顯示描述,則將函式名用作描述。

describe('some module', function() {
    // 使用命名函式
    beforeEach(function createSession() {
        // beforeEach: createSession
    })

    // 使用描述
    beforeEach('create a user session', function() {
        // beforeEach: create a user session
    })
})

根套件

在 describe() 塊外部定義 hooks 時,該鉤子便成為根級 hooks。根 hooks 適用於所有測試檔案,無論它們在何處定義。這是因為 Mocha 隱式建立了一個 describe() 塊,稱為根套件。

因此,在以下程式碼片段中,每個檔案中的每個測試之後都會觸發 afterEach() 掛鉤。

var tests = 1;

// 在任何檔案中的任何測試執行之後執行
afterEach(function() {
    console.log('Test #' + (tests++));
})

有時,您可能需要在執行任何測試套件之前執行非同步操作。Mocha 允許您透過使用 --delay 選項執行 mocha 二進位制檔案來延遲根套件。對於您的專案的測試命令, 它將如下所示:

npm test -- --delay

執行此命令指示 Mocha 將特殊的 run() 回撥函式附加到全域性上下文。呼叫 run() 函式將指示 Mocha 執行已描述的所有測試套件。因此,可以在非同步操作完成之後呼叫 run() 來執行測試。

例如,將以下程式碼片段新增到您先前建立的任何測試檔案中(它永遠不能在 it() 塊內):

// 將測試延遲到 5 秒後
setTimeout(function () {
    run();
}, 5000);

現在使用下面的命令執行測試:

npm test -- --delay

請注意,測試延遲了 5 秒鐘,然後執行。但是,如果不呼叫 run() 方法,則測試將永遠不會執行。輸出如下所示:

測試還不夠 - 確保您的應用正常執行

LogRocket 是一個前端日誌記錄工具,可以讓您像在您自己的瀏覽器中一樣重播問題。無需猜測錯誤發生的原因,或詢問使用者螢幕截圖和日誌檔案,LogRocket 使您可以重播會話以快速瞭解出了什麼問題。

除了記錄 Redux actions 和狀態外,LogRocket 還記錄控制檯日誌,JavaScript 錯誤,堆疊跟蹤,帶有請求頭 + 正文、瀏覽器後設資料和自定義網路日誌的網路請求/響應。它還使用 DOM 來記錄頁面上的 HTML 和 CSS,甚至可以為最複雜的單頁面應用程式重新建立畫素完美的影片。

控制測試

每當未將回撥函式作為第二個引數傳遞給 it() 時,測試用例就會標記為待處理(pending),這表明該測試尚未編寫。待處理測試不是失敗的測試,它們包含在測試結果中。

describe('#flattenArray()', function() {
    // 待處理測試
    it('should flatten array');
})

包括和排除測試

您還可以指定應該執行或不應該執行的測試套件和測試用例。Mocha 提供了兩種有用的方法:only()skip(),用於控制測試套件和測試用例的排它和包含行為。

使用 describe.skip() 方法組織套件中的測試執行,並使用 describe.only() 方法確保套件中的測試執行。

// 此測試套件中的測試將執行
describe.only('#flattenArray()', function() {
    it('should flatten array', function() { })
})

// 此測試套件中的測試無法執行
describe('#mergeArray()', function() {
    it('should merge two arrays', function() { })
})

使用 it() 的測試用例也是如此。透過在傳遞給 it() 的回撥函式中呼叫 this.skip() 可以在執行時跳過測試。這樣就可以根據某些條件動態跳過測試。

呼叫 this.skip() 有效地終止測試。因此最好的做法是避免在呼叫 this.skip() 之後執行其它命令。使用 this.skip() 在執行時跳過的每個測試都將標記為待處理測試(pending)。

describe.only('#flattenrray()', function() {
    // 這個測試將被執行
    it.only('should flatten array', function() { });

    // 這個測試無法執行
    it('should recursively flatten array', function() { });
})

describe.only('#mergeArray()', function() {
    // 對於生產環境,將在執行時跳過此測試
    // 在生產中,它將無法執行,並將被標記為待處理
    it('should merge two arrays', function() {
        if (process.env.NODE_ENV === 'production') {
            return this.skip();
        }
    })
})

測試環境輸出如下:

生產環境下,執行效果如下:

你可以多次使用 .only().skip() 選擇一組要執行的套件和測試。但是,您必須注意以下幾點:

  1. 巢狀套件仍將執行
  2. 如果過存在 hooks,仍將執行鉤子
  3. 測試將優先

重試測試

Mocha 提供了一種功能,用於指定可以重試失敗的測試的次數。不建議在單元測試中使用它,但是在編寫端到端測試(由於某些原因可能無法使用某外部資源)時,此功能很有用。

Mocha 提供了 this.retries() 函式,該函式可以讓您指定允許重試的次數。對於每次重試,Mocha 都會執行重新 beforeEach() 和 afterEach() hooks,但不會重新執行 before() 和 after() 鉤子。

以下程式碼片段顯示一個簡單的示例,改示例使用 Cypress 測試執行器訪問網頁。如果伺服器響應中的 status code 不是 2xx, 可能是因為網速慢或者網路連線不好,測試將被標記為失敗。

describe('test medium site', function() {
    // 這個套件中所有失敗的測試都會重試2次
    this.retries(2);

    it('should load medium homepage', function() {
        // 這個測試用例測試失敗後,會被重複5次
        this.retries(5);

        cy.visit('https://medium.com');
    })
})

使用 this.retries(5),這個測試允許在失敗後重試最多5次。

慢速的測試

Mocha 允許你指定一個時間長度,所有執行時間超過這個值的測試將被認為是慢速測試。可以使用 this.slow() 方法來達到這個目的。這個方法的引數是一個以毫秒為單位的數字。

describe('slow test', function() {
    // 在一秒之後,測試將被認為是緩慢的
    this.slow(1000);

    // 在指定的一秒鐘之後完成
    it('should be complete in a second', function(done) {
        setTimeout(done, 1500);
    })

    // 立即完成
    it('should be complete instantly', function() { })
})

注意上圖中用紅色文字標記的(1506)表示測試的執行時間,這條測試被認為是慢速測試,因為它的執行時間超過了 this.slow(1000) 中定義的1秒才執行完成。

超時時間

預設情況下,Mocha 測試執行時間最多為2秒(2000毫秒)。所有超過這個時間的測試都被認為超時。當一個測試超時時,這個測試被標記為失敗,並且會丟擲 timeout 錯誤。

但是,Mocha 提供了 this.timeout() 方法,用於設定給定的測試套件,hooks或者測試用例的超時時間。這個方法接收一個以毫秒為單位 int 數值作為引數。

可以在不同的級別(測試套件, hooks 或測試用例)配置不同的超時時間:

describe('some time-consuming operation', function() {
    // 給這個測試用例設定 5 秒的超時時間
    this.timeout(5000);

    before('some long step', function(done) {
        // 設定 hooks 的超時時間
        this.timeout(2500);

        setTimeout(done, 2250);
    })

    it('should take less than 200ms', function(done) {
        // 為當前測試用例設定超時時間
        this.timeout(200);

        setTimeout(done, 150);
    })
})

如果像關閉超時限制,則在呼叫 this.timeout() 時傳遞 0 即可。

describe('some time-consuming operation', function() {
    // 在這個測試用例中關閉超時限制
    this.timeout(0);

    it('should take a long time', function(done) {
        setTimeout(done, 10000);
    })
})

Mocha CLI 選項

到目前為止,您已經瞭解了 Mocha 所提供的用於編寫測試的所有工具。但是在使用 Mocha 時,仍然可以使用很多實用工具,並且只有在使用 Mocha CLI 時,才能使用的一些實用工具。

要獲取 Mocha CLI 所提供的可用選項列表,請執行以下命令:

mocha -h

在你的專案中,你可以實用下面的命令來代替:

npm test -- -h

監聽測試檔案

-w, --watch 標誌指示 Mocha 監聽測試檔案的變動並重新執行測試。這對於在開發過程中編寫測試非常有用。

mocha --watch

Async 和 bail

-A, --async-only 標誌強制所有測試必須傳遞迴調函式或返回一個 promise,從而非同步執行。對於未指定回撥函式或者未返回 promise 的測試將被標記為失敗。

mocha --async-only

-b, --bail 標誌指定只要有一個測試用例沒有透過,就停止後面所有的測試用例。這對於持續繼承很有用。

mocha --bail

處理超時和慢速測試

除了使用 this.timeout() 方法,還可以使用 -t, --timeout <ms> 來設定測試用例的超時時間。Mocha 的預設超時時間是2秒。你可以傳遞一個以毫秒為單位的數字來表示毫秒或者是帶(s)字尾的數字表示秒。

mocha -t 3000

等價於:

mocha --timeout 3s

如果要禁用超時限制,可以使用 --no-timeouts,這等價於 --timeout 0:

mocha --no-timeouts

同樣的,在 CLI 中也可以設定慢速測試的閾值,使用 -s, --slow <ms> 標誌。預設的閾值是 75ms。如你所見,Mocha 使用此閾值高亮顯示執行時間太長的測試。

mocha --slow 100

執行匹配的測試

Mocha 使用 -g, --grep <pattern> 標誌來透過正規表示式匹配需要執行的測試和測試套件。

前面我們已經提到過,透過 -f, --fgrep <string> 標誌可以匹配包含指定字串的測試和測試套件。

例如:下面命令執行所有包含 array 字串的測試和測試用例。

mocha -f array

匯入檔案和模組

-r, --require <module> 標誌允許您匯入在測試檔案中使用的模組/庫(例如斷言庫),而不是在程式碼中手動呼叫 require()。適用於諸如 should.js 之類的模組。但是要訪問模組的匯出(exports),您將必須在程式碼中 require 該模組。

mocha --require should

--file <file> 執行您新增一個或多個想要優先包含在測試套件中的檔案。這些檔案可能包含測試所需要的某些設定邏輯。--file 標誌可以多次使用以包含多個檔案。

Mocha 介面和報告

如前所示,Mocha 提供了多個用於編寫測試的介面。預設使用的是 BDD 介面,這是本指南中一直使用的介面。-u, --ui <name> 允許您指定另外一個需要使用的介面。

mocha --ui exports

透過 -R, --reporter <name> 標誌,您可以指定測試報告的格式。預設的是 spec格式。Mocha 還允許您使用此標誌指定第三方報告格式。

mocha -R list

除了 spec,官網還給出了其它許多報告格式

瀏覽器中的 Mocha

Mocha 測試執行程式也可以在瀏覽器中使用。Mocha 的每一個發行版都包含 ./mocha.css./mocha.js 用於在瀏覽器中使用。這裡是在瀏覽器上執行 Mocha 測試的簡單步驟。

設定公共檔案

在你的專案根目錄中建立一個 public 目錄。然後在 public 目錄中建立一個名為 index.html 的檔案,並新增下面的程式碼:

<!-- public/index.html -->

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Mocha Tests</title>

    <!-- Include Mocha CSS styles -->
    <link href="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css" rel="stylesheet">
</head>

<body>
    <div id="mocha"></div>

    <!-- Add the Chai assertion library -->
    <script src="http://chaijs.com/chai.js"></script>

    <!-- Add the Mocha test library -->
    <script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>

    <script>
    // Set chai.expect as a global variable
    var expect = chai.expect;

    // Setup Mocha to use the BDD interface
    mocha.setup('bdd');
    </script>

    <!-- Import the sum function -->
    <script src="/sum.js"></script>

    <!-- Import the tests for the sum function -->
    <script src="/sum.test.js"></script>

    <script>
    // Run the tests with Mocha
    mocha.run();
    </script>
</body>
</html>

我們將 Mocha 和 Chai 斷言庫的靜態 CSS 和 JS 檔案匯入到頁面中。<div id="mocha"></div> 元素用於顯示測試結果。

在設定 Chai 時,將 chai.expect 對映到名為 expect 的全域性變數上,以便可以在測試指令碼中使用它進行斷言。

透過呼叫 mocha.setup('bdd') 來告知 Mocha 選用 BDD 介面。使用 mocha.run() 方法執行測試。

接下來繼續在您之前建立的 public 目錄中建立一個名為 sum.js 的新檔案,並新增下面這些內容:

/* public/sum.js */

function sum() {
    // Convert argument object to array
    var args = Array.prototype.slice.call(arguments);

    // Throw error if arguments contain non-finite number values
    if (!args.every(Number.isFinite)) {
        throw new TypeError('sum() expects only numbers');
    }

    // Return the sum of the arguments
    return args.reduce(function(a, b) {
        return a + b;
    }, 0);
}

接下來繼續建立 sum.test.js 檔案,並新增下面內容:

/* public/sum.test.js */

describe('#sum()', function() {
    context('without arguments', function () {
        it('should return 0', function () {
            expect(sum()).to.equal(0);
        })
    })

    context('with number arguments', function () {
        it('should return sum of arguments', function () {
            expect(sum(1, 2, 3, 4, 5)).to.equal(15);
        })

        it('should return argument when only one argument is passed', function () {
            expect(sum(5)).to.equal(5);
        })
    })

    context('with non-number arguments', function () {
        it('should throw error', function() {
            expect(function() {
                sum(1, 2, '3', [4], 5)
            }).to.throw(TypeError, 'sum() expects only numbers.')
        })
    })
})

設定一個簡單的伺服器

接下來,可以選擇為公共檔案設定一個簡單的伺服器。在這個案例中,我們使用 live-server。繼續按照以下步驟將其安裝為專案依賴:

npm install --save-dev live-server

修改 pachage.json 檔案的 scripts 部分,使其包含用於提供公共檔案並在瀏覽器中執行 Mocha 測試的指令碼。它看起來應該是這樣:

/* package.json */
{
    "scripts": {
        "test": "mocha",
        "test:browser": "live-server --port=9000 --mount=/:public"
    }
}

我們在這裡新增了一個 test:browser 指令碼,已啟動 9000 埠來訪問 public 目錄中的檔案。

最後,我們在命令列中執行下面命令:

npm run test:browser

這應該在 9000 埠上啟動伺服器併為您啟動瀏覽器選項卡來展示它。瀏覽器上的測試輸出應該類似於下面圖片:

總結

在本指南中,您已經學習了在 Node.js 和瀏覽器上 Mocha 測試的基礎只是。您還學習瞭如何為 JavaScript 應用程式編寫和執行測試。

儘管本指南內容廣泛,但您始終可以參考 Mocha 文件以獲取本指南未涵蓋的各個方面。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章