簡介
日常我們都忙於寫bug
,有時候不妨停下腳步,找找bug
。測試廣義上分為黑盒測試和白盒測試。單元測試屬於後者,是在知道程式執行邏輯的基礎上,設計測試用例,確保程式模組行為與我們預期一致。
前端做單元測試的不多,但是並不代表不必要,對於一些複雜的資料處理、公共類庫等,單元測試是非常有必要的,程式碼只要有修改,就是有風險的,檢驗程式碼正確與否,最安全的方法就是通過設計的所有測試用例。通過本文,你將會收穫以下內容:
Node.js
中如何做單元測試,如何生成測試報告與測試覆蓋率vue.js
單檔案元件如何從零開始搭建單元測試環境
Node.js
單元測試
巧婦難為無米之炊,在做單元測試前,我們需要藉助一款測試框架與一個斷言庫,測試框架是輔助我們編寫測試用例,而斷言主要是用來判斷預期輸出與實際輸出是否一致。本文測試框架選用mocha,斷言採用expect.js。
CommonJS與ES6模組化區別
現在前端開發環境幾乎都執行在Node.js
中,只是最後打包成靜態資原始檔。所以單純只想針對單純專案中JavaScript
檔案進行單元測試,會因為模組化的差異而執行失敗,因為ES6
中使用的是import/export
,而CommonJS
中使用的是require/module.exports
,想了解Node.js 如何處理 ES6 模組,可以參考阮老師文章。本文推薦一個第三方類庫esm,僅需兩步就能實現Node.js
載入ES6 module
。使用流程如下:
- 安裝
npm install esm -D
- 使用
const $require = require('esm')(module)
// 注意:如果是export default,匯入的模組需要通過.default獲取
const TestModule = $require('ES6Module.js')
測試程式碼
以下為測試程式碼,主要測試加法運算及函式柯里化處理過程是否正確。
class Calc {
constructor() {
this.add = this.addFun()
}
// 函式柯里化
addFun () {
let args = []
let calcFun = function (...params) {
args = args.concat(params)
return args.reduce((total, current) => {
return total + current
}, 0)
}
calcFun.clear = function () {
args = []
}
return calcFun
}
}
export default = Calc
編寫測試用例
測試框架採用mocha
,一般編寫單元測試用例,離不開describe
和it
。describe
類似於開發中的class
,是一類測試用例的集合;it
相當於普通function
,是一個具體測試用例實現。如下為簡單的測試用例,簡單羅列了普通測試與非同步測試的基本使用,更多使用方法可以參考mocha官網
const Calc = require('../class/calc.js')
const expect = require('expect.js')
const calcInstance = new Calc()
describe('Test calc add operation', function () {
it('should 1 + 2 === 3', function () {
expect(calcInstance.add(1, 2)).to.be(3)
});
it('should summary + 2 === 4', function () {
expect(calcInstance.add(2)).to.be(5)
});
it('should 1 + 2 === 3 after clear', function () {
// 指定當前測試用例超時時間
this.timeout(0)
calcInstance.add.clear()
// 非同步測試
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 2000)
}).then(() => {
expect(calcInstance.add(1, 2)).to.be(3)
})
});
})
單元測試指標
覆蓋率簡述
覆蓋率是單元測試核心指標,又細分為語句覆蓋率(Statements
)、分支覆蓋率(Branches
)、函式覆蓋率(Functions
)、行覆蓋率(Lines
)。一個比較好的單元測試用例,要保證被測試程式碼的關鍵邏輯都被測試用例覆蓋到。如下為Calc
類的單元測試覆蓋率情況。
單元測試覆蓋率統計
開源元件nyc可以幫助我們統計覆蓋率情況。
- 安裝
npm install nyc -D
- 配置檔案
// nyc.config.js
module.exports = {
all: true,
include: [ // 包含測試檔案
"web/src/lib/**.js",
".electron/class/**.js",
"web/src/**/*.js",
"web/src/**/*.vue"
],
exclude: [ // 排除測試檔案
"web/test/*.spec.js",
".electron/test/*.spec.js"
],
checkCoverage: false, // 測試基準覆蓋率
reporter: ['text', 'html'] // 測試報告格式
}
- 使用
// package.json
"test-add": "nyc mocha .electron/test/calc.spec.js"
視覺化單元測試報告
mocha
官方推薦使用mochawesome
用於生成視覺化測試報告,使用非常簡單。
- 安裝
npm install mochawesome -D
- 使用
// package.json
"test-add-reporter": "mocha .electron/test/calc.spec.js --reporter mochawesome --reporter-options reportDir=mochaReporter,reportFilename=addReporter"
注意事項
編寫單元測試用例時,不僅要考慮測試覆蓋率,還要考慮測試用例設計。合格的測試用例不僅要包含正常情況輸入輸出,也要包含異常情況輸入輸出的判斷,不能以開發的思維去編寫測試用例。
vue元件的單元測試
vue
單檔案元件測試官方腳手架也有整合,但是還是要抱著試一試的態度,去學習下如何從零開始搭建一個vue
單檔案元件測試環境。
.vue
檔案並不能直接執行,需要對其進行打包編譯,轉換成瀏覽器能識別的靜態資原始檔才行。目前有開源的工具mochapack可以提供這種能力。見名知意,普通mocha
測試用例是可以直接執行的,但是遇到非javascript
語法,就會執行報錯。mochapack
主要功能是在測試用例執行前利用webpack
對測試用例進行編譯轉換,這樣就不用擔心執行出錯。具體配置如下:
// 基礎配置
{
"test-vue-sfc": "mochapack --webpack-config ./build/webpack.test.config.js --require ./web/test/setup.js web/test/demo.spec.js"
}
--webpack-config
指定webpack
配置檔案--require
指定環境依賴狀態,如nodejs
中不存在dom
,需要引入js-dom
web/test/demo.spec.js
需要執行的測試用例
vue測試用例編寫
測試用例是用nodejs
執行,並沒有瀏覽器環境,所以我們藉助官方提供的測試工具@vue/test-utils對元件進行模擬掛載、點選等。使用方法也比較簡單,以下為簡單的測試用例。
import Vue from 'vue'
import ElementUI from 'element-ui'
import TestDemo from '../src/components/test-demo.vue'
import { shallowMount } from '@vue/test-utils'
Vue.use(ElementUI)
describe('Test test-demo.vue', function () {
this.timeout(0)
const wrapper = shallowMount(TestDemo)
wrapper.vm.count = 1
it('should summary === 1', function () {
expect(wrapper.vm.summary).to.be(1)
});
})
結語
對於通用性、處理邏輯複雜等模組單元,做單元測試收益會很大的,至少每次改動的對錯,都能有一個較明顯的反饋。單元測試不僅要注意一定程度的覆蓋率,也要注意測試用例設計的合理性。完整程式碼可以參考electron-demo,這個專案是electron
開發demo
,裡面是本人日常開發中常見的坑點,有興趣的可以關注下。