Jest | 讓 Jest 為你的 Code 做測試-基礎用法教學

神Q超人
Enjoy life enjoy coding
8 min readFeb 5, 2019

--

Jest 的基本測試架構

前言

單元測試是進入前端工程後一直很想學的技能,主要是做過測試能讓自己的程式碼維持一定的水準,尤其在團隊開發時,更不會在上線時因為沒注意到某個細節而產生 Bug ,導致專案出現問題。

單元測試

單元測試是指為專案中每個單一行為做測試,通常專案裡的最小單位都是一個 function ,當每個 function 經過測試,確保邏輯是正確的,那當他在專案裡運行時也就比較不會發生問題,且留下的測試文件也可以在團隊討論或交接時更清楚。

Jest

用於前端的測試框架不是只有 Jest ,選擇原因是因為筆者較擅長使用 React ,而 Jest 在測試方面和 React 的整合度較佳。除了 Jest 以外,常聽到的測試框架還有 mocha

建立專案

首先到專案資料夾的目錄下,在 node.js 環境下創建 npm 專案:

npm init -y

這時候在專案資料夾內會產生記錄著專案開發設定的 package.json ,如果還不曉得如何安裝 node.js 可以參考「第一次建置node.js開發環境和安裝npm就上手!」的說明。

下載套件

透過 npm 套件管理工具下載 Jest 測試框架到專案的執行環境中:

npm install jest --save-dev

設定測試指令

打開 package.json ,可以看到剛剛下載的 Jest 已經被記錄在 devDependencies 中了:

下載在開發環境的 Jest 會被記錄在 package.json 中

在上圖第一行的 scripts 是在 npm 的開發環境中設定執行指令的地方,上方的 test 便是預設的指令之一,可以直接把他的內容改掉,如下:

scripts: {
"test": "jest"
}

設定好後,只需在終端機中使用以下方式輸入,便能執行設定好的對應指令:

npm run test //對應指令

需要注意的是,如果是使用 npmscripts 執行指令,那他的執行環境就是專案本身,尋找執行環境中的 Jest 或其他套件執行。

換個說法,直接在終端機中輸入 jest ,執行環境就不會在專案內,而是以全域為主,但是全域環境下並沒有安裝 Jest 便會出錯,除非將 Jest 安裝在全域中:

npm install jest -g  // -g 代表全域

建立測試

Jest 在執行測試時,會尋找專案中副檔名為 .test.js 結尾的檔案,但不限制要放在哪個資料夾,所以在根目錄新增一個 index.test.js 建立第一個測試:

把上方的 test 當作一個函式,負責描寫一個單元測試,他擁有兩個參數:

  1. 第一個參數為「測試名稱」,能夠簡單描述這部分是在測試什麼邏輯或功能。
  2. 第二個參數是一個函式,又稱斷言,函式內的 expect 用來描述被測試的內容, toBe 是測試內容的回傳值是否符合期望值,例如上方的測試內容為「5加上2期望會等於7」。

執行測試

在終端機中輸入在 scripts 中設定好的指令:

npm run test

執行後會顯示測試的結果:

通過 Jest 測試

結果內會顯示 Jest 測試了哪些 .test.js 檔案,還有每個測試( expect )內的結果( toBe )是否正確符合,符合的話會輸出 PASS。

現在把 toBe 內的數字改成 8 ,再進行一次測試:

未通過 Jset 測試

當測試失敗時, Jest 會再結果中顯示哪個檔案內的測試有問題,並會提示正確的結果 Received

這就是使用 Jest 測試的基本方法,但實際上需要測試的函式都已經寫好了,並不會在 expect 中寫下邏輯,因此可以直接在 expect 中呼叫函式,測試結果的正確性,例如:

其他斷言

斷言的種類有很多,上方的 toBe 只是其中一種測試方式,除此之外還有以下的斷言可以使用:

除了 toBe 外,對字串還可以用 toMatch 搭配正規表達式檢查:

確認物件是否等於期望值需使用 toEqual

預防函式回傳某個結果可以使用 not

上方的第 9 行 peopleA.name 是空的,而在使用 not 的情況下結果需不等於期望值,所以不會通過測試:

使用 not 測試代表結果需不等於期望值

確認數字結果的斷言:

需要注意在 JavaScript 中的小數點運算會產生誤差,因此浮點數需要使用 toBeCloseTo 做斷言,他會捨棄掉些微的誤差:

上方使用 toBe 會不通過測試,因為 toBe 需要完全符合:

JavaScript 的浮點數會出現誤差

對陣列可以用 toContain 判斷陣列內是否含有某值,或搭配迴圈對每個位置做斷言:

最後是用來判斷特殊值的斷言,例如 undefinednulltrue 等等:

產生覆蓋率報告

在測試的時候,會使用各種斷言來確認結果是否與期望值符合,但是如果測試的內容遺漏了某個條件分支,便無法確認該分支的邏輯性是否正確。

覆蓋率就是用來統計被測試的函式,程式碼的執行比例,當函式內所有程式都被測試過,那覆蓋率就會呈現 100% 。

另外, Jest 內建的覆蓋率會以每個 JavaScript 檔案統計,因此在產生前還需要將「函式」與「測試」檔案分開,如下:

建立 ./funcs/func.js 放要測試的函式:

func.js 中的 sum 有兩個分支,一個是在 b 有值的時候回傳 a + b ,另一個是在 b 沒有值的情況下直接回傳 a ,最後使用 module.exportssum 匯出。

接著建立測試檔案 ./__test__/index.test.js

最後到 package.json 中在 test 的指令後加上 --coverage ,讓 Jest 執行完時同步產生測試報告,當然也可以另外設定新指令:

在 jest 後方加上 — coverage

執行測試後,除了測試結果外,還會產生覆蓋率統計資訊:

覆蓋率的統計資訊,由左至右分別為:語法、分支、函式數、行數

也可以發現在專案目錄下多了一個叫做 converage 的資料夾,裡面的 Icov-report 內有個 index.html ,打開後也可以看到相同的資訊:

./converage/Icov-report/index.html

透過點擊 func.js 可以確認更詳細的測試過程,包含是哪一行沒有執行,或每行各執行了幾次:

紅色區塊代表未執行,也就是未覆蓋的地方,行數上的 1x 代表測試中執行次數

現在為 ./funcs/func.js 內的 sum 增加一個斷言句,讓 Jest 在測試時進入 sum 的另一個分支:

執行測試後再一次點開 converage 內的 html 測試報告:

覆蓋率已達 100%

func.js 的詳細執行資訊,在判斷 b 是否有值的地方執行了兩次,且已經沒有還未覆蓋的區塊:

已經沒有未覆蓋的區塊了

本文解釋了基本的 Jest 測試,並簡單描述斷言庫和產生覆蓋率報告,今後的文章會繼續解釋 Jest 提供的其他功能,一直到用於測試 ReactComponent 組件。

如果文章中有任何問題,或是不理解的地方,都歡迎留言告訴我,謝謝大家!

參考文章

  1. https://jestjs.io/docs/en/getting-started
  2. http://blog.404mzk.com/jest.html
  3. https://zhuanlan.zhihu.com/p/28247899

--

--