Vue組件庫工程探索與實踐之單元測試

本文是《Vue組件庫工程探索與實踐》系列文章第三篇,聊聊組件庫單元測試和持續集成功能的實現。javascript

單元測試是軟件工程領域的一個重要概念,指對軟件中的最小可測試單元進行檢查和驗證,它是代碼正確性驗證的最重要的工具。單元測試也是組件庫實現自動化測試與集成的基礎。html

單元測試會封閉執行最小化單元的代碼,使添加新功能和追蹤問題更容易。對代碼進行單元測試有不少好處:前端

  • 可節省手動測試的時間
  • 有助於減小開發新特性時產生的反作用
  • 有利於改進設計和重構
  • 有助於提高大團隊中複雜基礎代碼的可維護性

前端小夥伴們對單元測試多多少少都有必定的瞭解,但真正有實踐經驗的並不太多。我想可能與業務項目工期緊張、需求變化比變臉還快、對單元測試的意義認識不夠等方面因素有關。固然,也不是全部項目都須要單元測試。vue

程序猿是這麼死的

不過,隨着時間的推移,閱歷的累積,或許有一天你會真正意識到它的價值,就像李宗盛的歌。java

少年不聽李宗盛,聽懂已經是不惑年

對於組件庫這種可複用的公共代碼來講,其對可靠性、可維護性的要求較普通業務類項目代碼更高,引入單元測試是十分必要的。這裏分享一下咱們在Vue組件庫的單元測試方面的探索與實踐。node

限於篇幅,本文重點談Vue組件庫的單元測試功能及實現,不會過多介紹單元測試基礎知識。webpack

首先咱們須要明確,Vue組件庫的單元測試,主要仍是針對其中的Vue組件。git

Vue Test Utils

爲了方便對 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 是與測試運行器無關的,主流的測試運行器都支持。

官方推薦兩個測試運行器:Jestmocha-webpack

Jest 是 Facebook 開源的一套 JavaScript 測試框架, 它自動集成了斷言、JSDOM、覆蓋率報告等幾乎全部測試工具,功能至關強大。它所需的配置是最少的,不過須要一個可以將Vue單文件組件導入到測試中的預處理器。Vue.js官方提供了 vue-jest 預處理器來處理最多見的單文件組件特性,但仍不是 vue-loader 所有的功能。

mocha-webpack 是知名前端測試框架 Mochawebpack 的一個包裹器。下面這行命令就是它的大體工做原理:先對文件進行 webpack 編譯,再用 Mocha 對編譯後的文件進行測試。固然,其中還包含不少優化工做。

$ webpack test.js output.js && mocha output.js
複製代碼

所以咱們可以經過 webpack + vue-loader 獲得完整的Vue單文件組件支持。mocha-webpack 的配置比 Jest 複雜不少。

mocha-webpack2.0.0-beta.0版支持 webpack 4

爲了得到完整的Vue單文件組件支持,咱們在 NutUI 2.0 項目中選擇了 mocha-webpack 測試運行器。

瀏覽器環境

Vue.js 官方的測試工具庫 Vue Test Utils 依賴瀏覽器環境,而啓動真實的瀏覽器是很是複雜的,由於涉及到不一樣的平臺和版本,兼容性與穩定性不易處理。從另外一個角度看,自動測試一般不須要瀏覽器的用戶界面,使用無頭瀏覽器(headless browsers)就能知足需求。

無頭瀏覽器是一種沒有圖形用戶界面的網頁瀏覽器,能夠在相似於流行的 Web 瀏覽器的環境中提供對網頁的自動控制,經過命令行界面或使用網絡通訊來執行。它們能以與瀏覽器相同的方式渲染和理解 HTML,包括頁面佈局、顏色、字體選擇、JavaScript 與 Ajax 的執行等等。一般用於 Web 的自動化測試等場景。

當下比較流行的無頭瀏覽器有 JSDOMPuppeteerSelenium 等等,咱們的項目中選擇了 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,流行的斷言庫還有 chaiassertshould 等。

$ 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 目錄及文件,用來設置測試所需的全局環境。咱們在該文件中引入 JSDOMexpect

test/setup.js

require('jsdom-global')();
global.expect = require('expect');
複製代碼

接着,在 package.json文件中新增一個測試腳本。

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統計測試覆蓋率。

首先,咱們須要安裝 nycistanbul-instrumenter-loader:

$ npm install --save-dev nyc istanbul-instrumenter-loader
複製代碼
  • nyc: istanbul的命令行工具。
  • istanbul-instrumenter-loader: 使用鉤子(hooks)包裝代碼以在代碼執行時跟蹤覆蓋率的loader。

接下來,修改 package.json文件 scripts字段下 test腳本,同時增長 nyc的相關配置項:

package.json

{
  ...
  "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 用來指定被測試源文件的位置。
  • 禁用 nycinstrumentsourceMap 選項,由於這些工做應該由 loader 負責。

接下來須要把 istanbul-instrumenter-loader加到 webpack 的配置文件中。上文提到,咱們給單元測試工做指定的 webpack 配置文件是 webpack.test.conf.js,它與生產環境的配置文件有些差別,咱們先把生成環境的配置文件 webpack.prod.conf.js 導入,再把這些差別 merge 進去。

webpack.test.conf.js

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 必須放在數組的第一個,以確保它最後一個應用。
  • sourceMapmocha-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.ymlTravis 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 項目來講,installscript階段都有默認腳本,如不須要修改,能夠省略不寫。

  • install的默認腳本是:npm install
  • script的默認腳本是:npm test

Travis CI 還支持自動部署,但不是必須的。咱們的組件庫沒有用到,這裏很少說。

配置完成以後,每次往 Github 的該倉庫 push 代碼,都會觸發 CI。登陸 Travis CI網站能夠看到結果。

NutUI某次自動構建結果

咱們還能夠從 Travis CI 網站獲取一個關聯該倉庫 CI 結果的徽標,放在咱們項目的 README.md 文件中,這樣即使不登陸 Travis CI 網站,咱們也能夠經過該徽標知曉 CI 結果了。

CI結果徽標

測試覆蓋率上報

查看 NutUIREADME.md文件,會發現除了上文提到的CI結果徽標,還有一個展現測試覆蓋率的徽標。

這個徽標是經過 coveralls.io獲取的。 coveralls.io 提供測試覆蓋率的追蹤服務,咱們能夠把測試覆蓋率報告上報給 coveralls.io ,它會基於接收到的數據生成一個測試覆蓋率徽標。

coveralls.io 支持 Github 上的項目,也能夠與 Travis CI集成。關於它的具體使用,限於篇幅,這裏就不展開了,有興趣的小夥伴能夠閱讀其官方文檔。


好了,這篇文章先聊到這裏。若是對具體實現細節感興趣,能夠查看 NutUI 2.x 項目的源碼,也歡迎各位老鐵Star,贈人Star,手有餘香~

連接

相關文章
相關標籤/搜索