NODE.JS初學筆記14:利用mocha&chai去做簡單的單元測試(unit test)

前言

作為工程師必須熟知的概念之一便是測試,也就是在你撰寫程式碼時必須不斷的測試每個小部分是否真的完全沒問題,當日後專案規模擴大時才有利你自己或他人維護這個軟體。而今天要介紹的便是如何在node.js中利用mocha & chai兩個套件去做簡單的單元測試。

什麼是單元測試(Unit test)

單元測試正如同我們在前言中提到的,是去測試程式中最小的運作單位是否運行正常,也許是一個method或是一個function,像是新增會員的功能、結算加班費的函數等都屬於單元測試的範圍內。

利用mocha.js做第一個單元測試範例

mocha是一個可以在瀏覽器或是node中運行的測試框架,官方文件寫得非常的完善且容易理解,我個人很喜歡:P。首先我們在終端機輸入以下指令,注意這邊我之後要使用chai作為斷言庫,所以一併安裝。

npm i mocha chai

接著在你的專案目錄下新增test資料夾,並在其中建立test.js檔案。
在mocha框架下,若你沒有特別指定,測試時會自動跑所有在test資料夾下的js檔案,所以沒有特別需求的話,建議資料夾名稱不要做修改。

目前的專案結構(有些多餘的檔案是之前的遺物)

下一步請你修改package.json中的script部分,我們希望等一下跑測試可以直接在終端機跑。

package.json

 {
  "name": "unit_test_with_mocha",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "mocha test  --exit " //修改這行
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "chai": "^4.2.0",
    "config": "^3.2.2",
    "dotenv": "^8.1.0",
    "mocha": "^6.2.0"
  }
} 

這樣我們等一下就可以用npm test去做單元測試了,在開始前注意一下我後方寫入的option,你可以在test中加入一些常用選項幫助你做測試,以下是官方文件上比較常用的幾個選項。

–recursive 測試時一併測試子目錄下的所有指定類型檔案
–extension變更測試的檔案類型,預設為js
–exit測試完後自動結束mocha,隨著版本不同可能會變成不是預設值
–timeout設置測試的時間限制,超過設置的時間會被視為fail

官方文件目前是建議把–exit一同傳進test中,免得多出一些不必要的bug 。
以上步驟都完成後我們就可以在test.js中寫我們的第一個unit test!

test.js

//載入斷言庫
var assert = require('assert');
//描述測試的函數或功能
describe('Array', function() {   
  describe('#indexOf()', function() {
     //描述此測試案例的內容
     it('should return -1 when the value is not present', function() {
       //測試案例assert.equal中傳入了兩個參數,第一個是測試的功能,第二則是應回傳的值
       assert.equal([1, 2, 3].indexOf(4), -1);
     });
   }); 
}); 

可以看到上方大致可分為幾個區塊。
首先每一個describe便表示一個功能的測試,裡面的每一個it則是對應到一個測試的案例。也就是說一個describe下可能會有許許多多的it去做不同的案例測試。舉個例子來說,今天我要做會員註冊功能的測試,我測試的案例可能就會有成功輸入所有資料、少輸入email、兩次密碼不相同等不同的案例。一個好的單元測試應該要設想到所有可能的回傳結果。

最後我們在終端機輸入npm test 你就可以看到以下的結果。

測試成功的畫面

這樣我們就完成第一個單元測試了,非常的簡單,不過有個地方我們沒有細述,也就是assert的部份。

什麼是斷言庫

所謂斷言,簡單說就是在程式語言中判斷某段程式是否有回傳預期結果的一種邏輯判斷。斷言庫則是做判斷時的風格,基本上每種不同的斷言庫都能做到相同的事情,只是語法不太相同。我們剛剛使用的就是node內建的assert斷言庫,現在我們來介紹如何用另一種熱門的斷言庫chai來做到與剛剛相同的事情。

請先在test.js中引入chai中的expect方法。(其實還有另一種should斷言語法,但官方文件上較為推薦 expect ,除了相容性之外似乎在效能上也較為優秀)

test.js

var assert = require('assert');
const expect = require('chai').expect
const func = require('../func')


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); 註解此行 
      expect([1, 2, 3].includes(3)).to.be.false //加入這行,並動點手腳讓測試失敗
    });
  });
}); 

再次運行npm test,你應該會看到以下的結果。

可以看到錯誤的訊息出現,並告訴你預期的回傳值與實際回傳值。
這樣我們就用chai斷言庫去做出一樣的判斷囉,你可以注意到chai的語法上相當的直接易懂,就算不是開發者也可以一眼看出,以下列出幾個chai常見的斷言範例。

expect(42).to.equal(42)
expect(1).to.not.equal(true)
expect(1).to.be.ok (與to.be.false的差別在於這個方法會做轉型)
expect(false).to.be.false

結語

這篇文章中我們介紹了單元測試的基本概念,以及如何運用mocha框架與chai斷言庫去做簡單的單元測試,但實際上我們在做測試的並不會是如此單純的一行判斷式,每個功能都會扯到其他不同的功能,這時候我們要如何去做單元測試? 下一篇文章我們就會探討如何對常見的CURD流程做單元測試。

發表留言