使用 Mocha 和 Chai 測試 Node.js 代碼
編寫單元測試是很多人忘記做或完全避免做的事情之一,但是當你擁有它們時,它們就是救命稻草。
測試驅動開發,這意味著您在編寫代碼之前編寫測試,是一個值得努力的偉大目標,但在您編程時需要紀律和計劃。為了使整個過程變得更容易,您需要易於使用且功能強大的測試和斷言框架,這正是 Mocha 和 Chai 的特點。
在本文中,我將向您介紹這兩個庫,並向您展示如何結合使用它們來快速創建可讀且功能強大的單元測試。
柴
Chai 是一個斷言庫,它提供 BDD 和 TDD 兩種編程風格,用於在任何測試框架中測試您的代碼。
在本文中,我們將重點關注使用 Chai 的 expect
的 BDD 風格 界面。
expect
使用更自然的語言 API 來編寫您的斷言,這將使您的測試更容易編寫並在以後改進。這是通過將 getter 鏈接在一起來創建和執行斷言來完成的,從而更容易將需求轉換為代碼:
var user = {name: 'Scott'};
// Requirement: The object 'user' should have the property 'name'
expect(user).to.have.property('name');
這些 getter 的更多示例是:
to
be
is
and
has
have
其中相當多的 getter 可以鏈接在一起並與 true
等斷言方法一起使用 , ok
, exist
, 和 empty
在一行中創建一些複雜的斷言。舉幾個例子:
"use strict";
var expect = require('chai').expect;
// Simple assertions
expect({}).to.exist;
expect(26).to.equal(26);
expect(false).to.be.false;
expect('hello').to.be.string;
// Modifiers ('not')
expect([1, 2, 3]).to.not.be.empty;
// Complex chains
expect([1, 2, 3]).to.have.length.of.at.least(3);
可以在此處找到可用方法的完整列表。
您可能還想查看 Chai 的可用插件列表。這些使測試更複雜的功能變得更加容易。
以 chai-http 為例,它是一個幫助你測試服務器路由的插件。
"use strict";
var chai = require('chai');
var chaiHttp = require('chai-http');
chai.use(chaiHttp);
chai.request(app)
.put('/api/auth')
.send({username: '[email protected]', passsword: 'abc123'})
.end(function(err, res) {
expect(err).to.be.null;
expect(res).to.have.status(200);
});
摩卡
Mocha 是一個 Node.js 測試框架,它讓您可以靈活地串行運行異步(或同步)代碼。任何未捕獲的異常都會顯示在拋出異常的測試用例旁邊,便於準確識別失敗的原因和原因。
要使用 Mocha,我建議你使用 npm 全局安裝它:
$ npm install mocha -g
從 mocha
開始,您會希望它是全局安裝 命令用於在本地目錄中運行項目的測試。
使用 describe()
可以輕鬆創建測試用例 方法。 describe()
用於通過對其他 describe()
進行分組來為您的測試帶來結構 調用和 it()
方法一起,這是實際測試所在的位置。這可能最好用一個例子來描述:
"use strict";
var expect = require('chai').expect;
describe('Math', function() {
describe('#abs()', function() {
it('should return positive value of given negative number', function() {
expect(Math.abs(-5)).to.be.equal(5);
});
});
});
請注意,使用 Mocha 測試您不需要 require()
任何摩卡方法。這些方法在使用 mocha
運行時全局提供 命令。
為了運行這些測試,保存您的文件並使用 mocha
命令:
$ mocha .
Math
#abs()
✓ should return positive value of given number
1 passing (9ms)
輸出是運行的測試及其結果的細分。注意嵌套的 describe()
調用結轉到結果輸出。將給定方法或功能的所有測試嵌套在一起很有用。
這些方法是 Mocha 測試框架的基礎。使用它們來編寫和組織你喜歡的測試。我們將在下一節中看到一個例子。
寫作測試
在項目中組織測試的推薦方法是將所有測試放在自己的 /test
中 目錄。默認情況下,Mocha 使用 glob ./test/*.js
檢查單元測試 和 ./test/*.coffee
.從那裡,它將加載並執行任何調用 describe()
的文件 方法。
個人比較喜歡用後綴.test.js
對於實際包含 Mocha 測試的源文件。所以一個示例目錄結構可能如下所示:
├── package.json
├── lib
│ ├── db.js
│ ├── models.js
│ └── util.js
└── test
├── db.test.js
├── models.test.js
├── util.test.js
└── util.js
util.js
不會包含任何實際的單元測試,只是幫助測試的實用函數。
您可以使用任何對您有意義的結構(這是 Mocha 的優點),但過去這對我來說效果很好。
在實際編寫測試時,使用 describe()
來組織測試很有幫助 方法。您可以按特性、功能、文件或其他方式組織它們。
擴展上一節中的示例,我們將選擇按功能組織測試,結果如下所示:
免費電子書:Git Essentials
查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!
"use strict";
var expect = require('chai').expect;
describe('Math', function() {
describe('#abs()', function() {
it('should return positive value of given negative number', function() {
expect(Math.abs(-5)).to.be.equal(5);
});
it('should return positive value of given positive number', function() {
expect(Math.abs(3)).to.be.equal(3);
});
it('should return 0 given 0', function() {
expect(Math.abs(0)).to.be.equal(0);
});
});
});
然後運行測試會給你輸出:
$ mocha .
Math
#abs()
✓ should return positive value of given negative number
✓ should return positive value of given positive number
✓ should return 0 given 0
3 passing (11ms)
進一步擴展(我保證,這是我將展示的最後一個),您甚至可以在一個文件中測試多個方法。在這種情況下,方法按 Math
分組 對象:
"use strict";
var expect = require('chai').expect;
describe('Math', function() {
describe('#abs()', function() {
it('should return positive value of given negative number', function() {
expect(Math.abs(-5)).to.be.equal(5);
});
it('should return positive value of given positive number', function() {
expect(Math.abs(3)).to.be.equal(3);
});
it('should return 0 given 0', function() {
expect(Math.abs(0)).to.be.equal(0);
});
});
describe('#sqrt()', function() {
it('should return the square root of a given positive number', function() {
expect(Math.sqrt(25)).to.be.equal(5);
});
it('should return NaN for a given negative number', function() {
expect(Math.sqrt(-9)).to.be.NaN;
});
it('should return 0 given 0', function() {
expect(Math.sqrt(0)).to.be.equal(0);
});
});
});
輸出:
$ mocha .
Math
#abs()
✓ should return positive value of given negative number
✓ should return positive value of given positive number
✓ should return 0 given 0
#sqrt()
✓ should return the square root of a given positive number
✓ should return NaN for a given negative number
✓ should return 0 given 0
6 passing (10ms)
好的,你明白了。
不可否認,大多數單元測試並不是這麼簡單。很多時候,您可能需要其他資源來執行測試,例如數據庫或其他一些外部資源。為了進行設置,我們可以使用以下一種或多種 Mocha 掛鉤方法:
before()
:在給定塊中的所有測試之前運行beforeEach()
:在給定塊中的每個測試之前運行after()
:在給定塊中的所有測試之後運行afterEach()
:在給定塊中的每個測試之後運行
這些鉤子是執行測試所需的設置和拆卸工作的理想場所。正如我已經提到的,常見的用例之一是在運行測試之前建立與數據庫的連接,如下例所示:
"use strict";
var expect = require('chai').expect;
var Camo = require('camo');
var User = require('../models').User;
describe('Users', function() {
var database = null;
before(function(done) {
Camo.connect('mongodb://localhost/app_test').then(function(db) {
database = db;
return database.dropDatabase();
}).then(function() {}).then(done, done);
});
afterEach(function(done) {
database.dropDatabase().then(function() {}).then(done, done);
});
describe('#save()', function() {
it('should save User data to database', function(done) {
// Use your database here...
});
});
describe('#load()', function() {
it('should load User data from database', function(done) {
// Use your database here...
});
});
});
在任何之前 運行測試,函數發送到我們的 before()
方法運行(並且在整個測試中只運行一次),它建立到數據庫的連接。完成後,我們的測試套件就會運行。
由於我們不希望一個測試套件中的數據影響我們的其他測試,因此我們需要在每個套件運行後清除數據庫中的數據。這就是 afterEach()
是為了。我們使用這個鉤子來清除each之後的所有數據庫數據 測試用例已運行,因此我們可以從頭開始進行下一個測試。
運行測試
對於大多數情況,這部分非常簡單。假設你已經安裝了 Mocha 並導航到項目目錄,大多數項目只需要使用 mocha
沒有參數的命令來運行他們的測試。
$ mocha
Math
#abs()
✓ should return positive value of given negative number
✓ should return positive value of given positive number
✓ should return 0 given 0
#sqrt()
✓ should return the square root of a given positive number
✓ should return NaN for a given negative number
✓ should return 0 given 0
6 passing (10ms)
這與我們之前的示例略有不同,因為我們不需要告訴 Mocha 我們的測試位於何處。在此示例中,測試代碼位於 /test
的預期位置 .
但是,在運行測試時,您可能需要使用一些有用的選項。例如,如果您的某些測試失敗,您可能不想在每次進行更改時都運行整個套件。對於某些項目,完整的測試套件可能需要幾分鐘才能完成。如果你真的只需要運行一個測試,那會浪費很多時間。
對於這樣的情況,您應該告訴 Mocha 要運行哪些測試。這可以使用 -g <pattern>
來完成 或 -f <sub-string>
選項。
同樣,使用上面的示例,我們可以使用 -g
僅運行我們的 #sqrt()
的選項 測試:
$ mocha -g sqrt
Math
#sqrt()
✓ should return the square root of a given positive number
✓ should return NaN for a given negative number
✓ should return 0 given 0
3 passing (10ms)
注意 #abs()
本次運行中不包括測試。如果您對測試名稱進行相應計劃,則可以使用此選項僅運行測試的特定部分。
然而,這些並不是唯一有用的選項。以下是您可能想要查看的更多 Mocha 選項:
--invert
:反轉-g
和-f
匹配--recursive
:包括子目錄--harmony
:在 Node 中啟用所有和聲功能
您可以使用 mocha -h
查看完整的選項列表 命令,或在此頁面上。
在哪裡了解更多信息
這個主題的內容遠遠超過我們在一篇簡短的博客文章中所能涵蓋的內容,所以如果您想了解更多信息,我建議您查看以下資源:
- Mocha 文檔
- Chai 文檔
除了閱讀文檔之外,您還可以嘗試有關該主題的課程,我在下面鏈接到該課程。講師詳細介紹瞭如何使用 Mocha、Chai 和 Sinon 進行設置以測試 Node.js 代碼,以及每個主題的深入視頻。
使用 Mocha、Chai 和 Sinon 學習 Javascript 單元測試
是對本文的一個很好的補充,視頻格式也比文檔網站更容易消化。
結論
請記住,Mocha 和 Chai 都可以用於測試幾乎任何類型的 Node 項目,無論是庫、命令行工具,甚至是網站。利用您可用的各種選項和插件,您應該能夠很容易地滿足您的測試需求。這些庫中的每一個對於驗證您的代碼都非常有用,並且應該在幾乎所有的 Node 項目中使用。
希望這可以作為對 Mocha 和 Chai 的有用介紹。除了我在這裡介紹的內容之外,還有很多東西需要學習,因此請務必查看文檔以獲取更多信息。
對於編寫 Mocha/Chai 測試有什麼有用的提示嗎?請在評論中告訴我們!