本文是《Vue組件庫工程探索與實踐》系列文章第三篇,聊聊組件庫單元測試和持續集成功能的實現。javascript
單元測試是軟件工程領域的一個重要概念,指對軟件中的最小可測試單元進行檢查和驗證,它是代碼正確性驗證的最重要的工具。單元測試也是組件庫實現自動化測試與集成的基礎。html
單元測試會封閉執行最小化單元的代碼,使添加新功能和追蹤問題更容易。對代碼進行單元測試有不少好處:前端
前端小夥伴們對單元測試多多少少都有必定的瞭解,但真正有實踐經驗的並不太多。我想可能與業務項目工期緊張、需求變化比變臉還快、對單元測試的意義認識不夠等方面因素有關。固然,也不是全部項目都須要單元測試。vue
不過,隨着時間的推移,閱歷的累積,或許有一天你會真正意識到它的價值,就像李宗盛的歌。java
對於組件庫這種可複用的公共代碼來講,其對可靠性、可維護性的要求較普通業務類項目代碼更高,引入單元測試是十分必要的。這裏分享一下咱們在Vue組件庫的單元測試方面的探索與實踐。node
限於篇幅,本文重點談Vue組件庫的單元測試功能及實現,不會過多介紹單元測試基礎知識。webpack
首先咱們須要明確,Vue組件庫的單元測試,主要仍是針對其中的Vue組件。git
爲了方便對 Vue 單文件組件進行測試,Vue.js 官方提供了測試工具庫 Vue Test Utils
,它提供了一系列方法用於測試Vue組件。github
Vue Test Utils
經過把組件隔離掛載,模擬必要的輸入 (prop、注入和用戶事件) 和對輸出 (渲染結果、觸發的自定義事件) 的斷言來測試 Vue 組件。被掛載的組件會返回到一個包裹器內,而包裹器會暴露不少封裝、遍歷和查詢其內部的 Vue 組件實例的便捷的方法。此外,Vue Test Utils
還提供了模擬用戶交互的相關方法。web
可見,Vue Test Utils
是 Vue 組件單元測試的必備工具,須要安裝。
$ npm install --save-dev @vue/test-utils
複製代碼
測試運行器 test runner
即運行測試的程序,也就是咱們一般所說的測試框架。Vue Test Utils
是與測試運行器無關的,主流的測試運行器都支持。
官方推薦兩個測試運行器:Jest
和 mocha-webpack
。
Jest
是 Facebook 開源的一套 JavaScript
測試框架, 它自動集成了斷言、JSDOM、覆蓋率報告等幾乎全部測試工具,功能至關強大。它所需的配置是最少的,不過須要一個可以將Vue單文件組件導入到測試中的預處理器。Vue.js
官方提供了 vue-jest
預處理器來處理最多見的單文件組件特性,但仍不是 vue-loader
所有的功能。
而 mocha-webpack
是知名前端測試框架 Mocha
與 webpack
的一個包裹器。下面這行命令就是它的大體工做原理:先對文件進行 webpack
編譯,再用 Mocha
對編譯後的文件進行測試。固然,其中還包含不少優化工做。
$ webpack test.js output.js && mocha output.js
複製代碼
所以咱們可以經過 webpack + vue-loader
獲得完整的Vue單文件組件支持。mocha-webpack
的配置比 Jest
複雜不少。
mocha-webpack
的2.0.0-beta.0
版支持webpack 4
爲了得到完整的Vue單文件組件支持,咱們在 NutUI 2.0
項目中選擇了 mocha-webpack
測試運行器。
Vue.js 官方的測試工具庫 Vue Test Utils
依賴瀏覽器環境,而啓動真實的瀏覽器是很是複雜的,由於涉及到不一樣的平臺和版本,兼容性與穩定性不易處理。從另外一個角度看,自動測試一般不須要瀏覽器的用戶界面,使用無頭瀏覽器(headless browsers
)就能知足需求。
無頭瀏覽器是一種沒有圖形用戶界面的網頁瀏覽器,能夠在相似於流行的 Web 瀏覽器的環境中提供對網頁的自動控制,經過命令行界面或使用網絡通訊來執行。它們能以與瀏覽器相同的方式渲染和理解 HTML,包括頁面佈局、顏色、字體選擇、JavaScript 與 Ajax 的執行等等。一般用於 Web 的自動化測試等場景。
當下比較流行的無頭瀏覽器有 JSDOM、Puppeteer、Selenium 等等,咱們的項目中選擇了 JSDOM
在 Node 虛擬瀏覽器環境運行測試。
$ npm install --save-dev jsdom jsdom-global
複製代碼
// 在測試的配置文件中
require('jsdom-global')()
複製代碼
「斷言」就是判斷代碼的實際執行結果與預期結果是否一致,若是不一致就拋出一個錯誤。全部的測試用例都應該包含至少一條斷言。它是編寫測試用例的關鍵。
好比下面這條斷言,它的含義是調用 add(1,1)
的結果應該等於2。
expect(add(1,1)).to.be.equal(2);
複製代碼
斷言功能由斷言庫來實現。Jest
框架內置了斷言庫 expect
,而 Mocha
不包含斷言庫。因此選擇使用 Mocha
框架的時候,咱們還須要額外安裝一個斷言庫。
expect
斷言風格(如上面的栗子)很接近天然語言,NutUI 2.x
項目的斷言庫選用的也是 expect
。除了 expect
,流行的斷言庫還有 chai
、assert
、should
等。
$ npm install --save-dev expect
複製代碼
在測試的配置文件中引入 expect
,並把它掛到全局對象上,固然也能夠在每一個測試文件中分別導入。
global.expect = require('expect')
複製代碼
在肯定了測試運行器使用 mocha-webpack
,瀏覽器環境使用 JSDOM
,斷言庫使用 expect
以後,咱們就能夠開始在組件庫腳手架中進行測試工具的安裝和配置了。
首先安裝測試所需依賴。
$ npm install --save-dev @vue/test-utils mocha mocha-webpack@2.0.0-beta.0 expect jsdom jsdom-global
複製代碼
而後,在項目根目錄下新建 test/setup.js
目錄及文件,用來設置測試所需的全局環境。咱們在該文件中引入 JSDOM
和 expect
。
require('jsdom-global')();
global.expect = require('expect');
複製代碼
接着,在 package.json
文件中新增一個測試腳本。
{
"scripts": {
"test": "mocha-webpack --webpack-config webpack.test.conf.js --require test/setup.js src/packages/*/__test__/**.spec.js"
}
}
複製代碼
--webpack-config
指定了測試使用的 webpack 配置文件 webpack.test.conf.js
。該文件與生產環境配置文件有些差別,下文會細說。--require
標識確保文件 test/setup.js
在測試以前運行,所以咱們能夠在該文件中設置測試所需的全局環境。測試覆蓋率是對測試徹底程度的度量,是由測試需求、測試用例的覆蓋或已執行代碼的覆蓋表示的。
一個統計 JavaScript
單元測試覆蓋率的知名工具是 istanbul
,它以土耳其最大城市伊斯坦布爾命名,由於土耳其地毯世界聞名,而地毯是用來覆蓋的。
咱們來看下在 mocha-webpack
框架下,如何使用 istanbul
統計測試覆蓋率。
首先,咱們須要安裝 nyc
和 istanbul-instrumenter-loader
:
$ npm install --save-dev nyc istanbul-instrumenter-loader
複製代碼
nyc
: istanbul
的命令行工具。istanbul-instrumenter-loader
: 使用鉤子(hooks)包裝代碼以在代碼執行時跟蹤覆蓋率的loader。接下來,修改 package.json
文件 scripts
字段下 test
腳本,同時增長 nyc
的相關配置項:
{
...
"scripts": {
"test": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text mocha-webpack --webpack-config build/webpack.test.conf.js --require test/setup.js src/packages/*/__test__/**.spec.js"
...
},
"nyc": {
"include": [
"src/packages/**/*.vue"
],
"instrument": false,
"sourceMap": false
},
...
}
複製代碼
test
腳本中 --reporter=lcov --reporter=text
是配置 nyc
同時輸出lcov (lcov.info + html)
和文本形式的覆蓋率報告。
而 scripts
字段下方 nyc
的配置項中:
include
用來指定被測試源文件的位置。nyc
的 instrument
和 sourceMap
選項,由於這些工做應該由 loader 負責。接下來須要把 istanbul-instrumenter-loader
加到 webpack 的配置文件中。上文提到,咱們給單元測試工做指定的 webpack 配置文件是 webpack.test.conf.js
,它與生產環境的配置文件有些差別,咱們先把生成環境的配置文件 webpack.prod.conf.js
導入,再把這些差別 merge 進去。
const path = require('path');
const prodConf = require('./webpack.prod.conf.js');
const merge = require('webpack-merge');
module.exports = merge(prodConf, {
module: {
rules: [
{
test: /\.(js|ts)/,
use: {
loader: 'istanbul-instrumenter-loader',
options: { esModules: true }
},
include: path.resolve(__dirname, '../src/packages/')
},
],
},
devtool: 'inline-cheap-module-source-map',
externals: [require('webpack-node-externals')()]
});
複製代碼
js/ts
類型的文件新增了 loader: istanbul-instrumenter-loader
,要注意的是,該 loader 必須放在數組的第一個,以確保它最後一個應用。sourceMap
在 mocha-webpack
中必須經過內聯方式獲取,因此 devtool
選項推薦的值爲 inline-cheap-module-source-map
。webpack-node-externals
外置全部的 NPM 依賴。至此,整個項目的自動化測試功能及覆蓋率統計配置基本完成,咱們在 src/packages/
目錄下的每一個組件的目錄下新建一個__test__
目錄,該目錄下的單元測試文件以 .spec.js
做爲擴展名。
準備好組件的單元測試文件以後,在終端執行 npm test
便可啓動測試。測試的過程當中,終端會展現每一個測試用例的測試結果。
測試結束以後,終端會以文本形式展現出本次測試的覆蓋率報告,同時 /coverage
目錄下也會生成測試覆蓋率報告文件(Icov.info+html)。
持續集成(Continuous Integration, CI)是一種軟件開發實踐,即每次代碼的集成都經過自動化的構建(包括編譯/發佈/自動化測試)來驗證,從而儘早的發現集成錯誤。也就是說,只要代碼有變動,就自動運行構建和測試,確保符合預期後,再將新代碼集成到主幹。它的核心措施是,在代碼集成到主幹以前,必須經過自動化測試。
持續集成的意義在於:
Travis CI 是在線託管的 CI
服務,使用 Travis
來進行持續集成。它對於開源項目是免費的,支持綁定 Github 上面的項目。只要有新的代碼,就會自動抓取。而後,提供一個運行環境,自動進行構建和測試,還支持部署到服務器。
咱們來看下 Travis CI
的基本用法。
首先,訪問 Travis CI 官網並使用 Github 帳戶登陸。 而後,點擊其網站右上角的我的頭像,網頁會列出 Github 上咱們和咱們所在的組織的全部代碼倉庫。打開須要進行 CI
的倉庫右側的開關便可。
接下來,咱們須要在這個代碼倉庫的根目錄放置一個名爲 .travis.yml
的 Travis CI
配置文件。NutUI 2.x
項目的配置文件內容以下:
sudo: required
language: node_js
node_js:
- '8'
script:
- npm test
- npm run coveralls
複製代碼
sudo: required
表示須要 sudo
權限。language: node_js
指定運行環境爲 Node 。node_js
字段用來指定 Node 版本。script
字段用來指定構建或者測試的腳本。Travis
的運行流程包含兩個階段:install
(安裝依賴)和 script
(執行腳本)。對於 Node 項目來講,install
和script
階段都有默認腳本,如不須要修改,能夠省略不寫。
install
的默認腳本是:npm install
。script
的默認腳本是:npm test
。Travis CI
還支持自動部署,但不是必須的。咱們的組件庫沒有用到,這裏很少說。
配置完成以後,每次往 Github 的該倉庫 push 代碼,都會觸發 CI
。登陸 Travis CI
網站能夠看到結果。
咱們還能夠從 Travis CI
網站獲取一個關聯該倉庫 CI
結果的徽標,放在咱們項目的 README.md
文件中,這樣即使不登陸 Travis CI
網站,咱們也能夠經過該徽標知曉 CI
結果了。
查看 NutUI 的 README.md
文件,會發現除了上文提到的CI結果徽標,還有一個展現測試覆蓋率的徽標。
這個徽標是經過 coveralls.io
獲取的。 coveralls.io
提供測試覆蓋率的追蹤服務,咱們能夠把測試覆蓋率報告上報給 coveralls.io
,它會基於接收到的數據生成一個測試覆蓋率徽標。
coveralls.io
支持 Github 上的項目,也能夠與 Travis CI
集成。關於它的具體使用,限於篇幅,這裏就不展開了,有興趣的小夥伴能夠閱讀其官方文檔。
好了,這篇文章先聊到這裏。若是對具體實現細節感興趣,能夠查看 NutUI 2.x 項目的源碼,也歡迎各位老鐵Star,贈人Star,手有餘香~