Mocha.js 與 Babel 7 的組合

之前的一段時間,為了單元測試的結果最接近實際結果,因此希望能夠與産品一樣在瀏覽器內進行,
因此使用 Karma.js 搭配 chrome 下執行,運作的時候會多一個作為測試的 chrome 瀏覽器。

後來覺得,既使使用 chrome 來測試,也不能代表在 IE, Safari, FireFox 下都能絕對正確地運作,
單元測試主要針對資料處理、數值運算的檢查,跑在同樣以 V8 引擎為基底的 Node.js 上應該沒太多差別。
就算小部分的不同,與少開啟一個瀏覽器所增加的測試效率相比,在 Node.js 下測試比較有利。

藉由將專案的 Babel 版本升級到 7,重新串接單元測試的流程,並將過程記錄下來。

升級 babel 7

由於新版本的 babel 已經不是使用原來的那個模組名稱,因此要先把舊的模組移掉,重新安裝新的。

官方建議可以使用 babel-upgrade 工具來進行升級。

npx babel-upgrade --write

如果沒有加上 --write 的話,只會看到升級將會異動的部分,並不會實際對 package.json 進行修改。

由於使用 babel-upgrade 會讓 package.json 裡多許多套件,雖然實際上安裝的模組不見得真的變多,
但是看到那些多出來的設定值,還是有點不痛快,因為同時要移除 Karma.js ,決定要自己動手。

npm uninstall babel-core babel-preset-env babel-preset-stage-0

# 或是

yarn remove babel-core babel-preset-env babel-preset-stage-0

安裝新模組…

npm install -D @babel/core @babel/preset-env @babel/register

# 或

yarn add --dev @babel/core @babel/preset-env @babel/register

新增 / 移除的模組,要看各別的專案需求,上面只是一個例子。
babel-preset-stage-0 來說,以往是對於物件擴展(spread)的語法支援,
在 babel 7 中被整合到 @babel/preset-env 裡了,所以上述的例子中,不需要多安裝 @babel/preset-stage-0

以後面這種安裝,讓 package.json 只要記錄 @babel/core@babel/preset-env@babel/register 三者就好,
清爽許多,如果是新的專案,前兩者再加上 babel-loader 模組就可以與 webpack 搭配進行編譯,
而最後的 @babel/register 則是為了讓 Mocha.js 在 Node.js 下能夠讀懂 ES6 的一些語法。

設定 Babel

新版的 babel 建議使用 babel.config.js 取代 .babelrc 檔案,
因此我將既有的 .babelrc 刪掉,建立 babel.config.js 在裡面寫下…

const presets = [
  [
    "@babel/preset-env",
  ],
];

module.exports = { presets };

這樣就完成了 babel 的設定,相較原來要決定使用的 stage ,新版簡單了許多。

安裝 Mocha.js

除了移除不再使用的 Karma.js 之外,這次也升級了 Mocha.js 的相關模組,
畢竟都是快一年前的專案,跟著搭配新的 babel 模組,最近的模組總是比較不會遇到問題。

npm install -D mocha chai

# 或

yarn add --dev mocha chai

先安裝這兩個模組,讓既有的測試程式能夠跑得起來,再去處理其它部分。

package.jsonscripts 增加了 "test": "mocha -w -r @babel/register"
如此可以使用 npm run testyarn test 的方式開始單元測試。
-r 的意思就是引入 @babel/register 模組,它會在程式開始解析

至於單元測試要怎麼實作,就不在這篇文章的討論範圍內,可以參考網路上的其它教學。

測試覆蓋率統計

知道測試的中執行到的程式,佔所有被測檔案中的百分比是重要的,
能夠了解是否具有過多的程式碼是未被測試程式驗證的。

這裡使用的是 istanbuljs ,其官方網站推薦使用 nyc 模組來執行。

npm install -D nyc

# 或

yarn add --dev nyc

安裝完之後在 package.jsonscripts 加上 "coverage": "nyc mocha -r @babel/register"
就可以用 npm run coverageyarn coverage 來執行測試,並加上覆蓋率的檢查。

將單元測試與覆率檢查分開的原因

之前使用 Karma.js 時,我是把單元測試與覆蓋率檢查放在同一個任務中,
每當程式碼有異動的時候,就重新執行一次單元測試並統計該次的測試覆蓋率。

Karma.js 拿開後,發現 nyc 模組並不支援 Mocha.js 的 watch 功能,
每次測試結束並不會顯示該次的覆蓋率統計,一直到按下 Ctrl + C 終止 Mocha.js 後才會顯示。
沒有辦法即時顯示就失去了與持續單元測試一同執行的原意。

嘗試使用 watchnodemon 這兩個模組,將 nyc 再包入其中執行,
結果雖然可以即時重作測試並進行統計,不過反應速度與 Mocha.js 原生的 --watch 相比慢了許多。
認為覆蓋率通常是在測試程式大體寫完,在抓漏的時候才會用到,因此決定將兩著拆開在不同的 scripts 項目中。

除了上述兩個 node modules ,還找到了另一個叫 mochista 的模組,
它是整合了 Mocha.js 與另一個統計覆蓋率,叫作 c8 的模組一同運作。
只是在測試的時候,發現它似乎只能針對 Node.js 原生支援的程式才能運作,
對於我手上都需要以 babel 轉譯的專案,統計的結束總是一片空。
最後放棄這條路,未來如果有機會再作更深入的研究。