單元測試是什麼
對軟件中的最小可測試單元(一個方法)進行測試
單元測試的意義
1、分模塊開發,方便定位到哪個模塊出現問題
2、保證了代碼質量
3、驅動開發(先寫單元測試,通過再寫代碼)
單元測試兩種類型
TDD(測試驅動開發,從需求角度出發)
我需要的結果是什麼?如果不是即爲錯誤
針對於數據,面向的是最終的值,適用於開發人員
開發流程:需求分析->編寫單元測試->編寫代碼使單元測試通過->重構
BDD(行爲驅動開發,從具體功能角度出發)
結果應該是什麼?如果不是即爲錯誤
面向的是最終的產出效果,適用於需求客戶人員
開發流程:從業務角度定義目標->找到實現目標的方法->編寫單元測試->實現行爲->檢查產品
單元測試核心內容
測試框架
幫助測試得以運行
Jest-基於Jasmine,對react友好
Jasmine-BDD風格,自帶assert和mock(大集成)
Mocha-全面適合node和瀏覽器兩端
Qunit-出自jquery,後來獨立出來
斷言庫(assert)
幫助檢查結果
chai-支持所有風格,全面
Assert-node環境直接使用
Mock庫
幫助屏蔽方法、數據及相關依賴,避免外部數據對測試產生影響
sinon
test runner
提供運行環境,使得方法能夠運行
karma
覆蓋率工具
測試比例,明確測試了多少內容
istanbul
單元測試組成部分
測試人員與前端單元測試工作區別
測試用例(測試人員編寫)
爲了某個特殊目標而編織的一系列測試輸入,執行以及輸出結果,來測試是否滿足需求
單元測試(前端編寫)
以Vue爲實例編寫單元測試
1、腳手架安裝項目,選擇單元測試
2、生成目錄如下
karma.conf.js配置文件說明
var webpackConfig = require('../../build/webpack.test.conf')
module.exports = function karmaConfig (config) {
config.set({
//模擬環境
browsers: ['PhantomJS'],//無頭瀏覽器,不屬於任何廠家,單純的一個javascript執行環境
//所用到的各種庫,mocha框架,sinon-chai斷言庫
frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
//覆蓋率暴露到哪裏
reporters: ['spec', 'coverage'],
//需要加載到瀏覽器的文件
files: ['./index.js'],
//使用前的處理
preprocessors: {
'./index.js': ['webpack', 'sourcemap']
},
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
//指定報告輸出的類型和目錄
coverageReporter: {
dir: './coverage',
reporters: [
{ type: 'lcov', subdir: '.' },
{ type: 'text-summary' }
]
}
})
}
index.js文件說明
import Vue from 'vue'
Vue.config.productionTip = false
//require.context將指定路徑下所有符合規則的文件都引入
const testsContext = require.context('./specs', true, /\.spec$/)
testsContext.keys().forEach(testsContext)
//業務代碼引入
const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/)
srcContext.keys().forEach(srcContext)
3、編寫單元測試
.spec.js文件下編寫單元測試
import Vue from 'vue'
import HelloWorld from '@/components/HelloWorld'
import axios from 'axios'
import { expect } from 'chai'
//整個組件測試描述
describe('HelloWorld.vue', () => {
//拿到當前組件的構造函數
const Constructor = Vue.extend(HelloWorld)
//掛載,模擬渲染過程
const vm = new Constructor().$mount()
//每一個it就是對於一個方法的單元測試
//描述測試
it('should render correct contents', () => {
expect(vm.$el.querySelector('.hello h1').textContent)
.to.equal('Welcome to Your Vue.js App')
})
//檢測一個方法
it('m1 should add two arguments', () => {
const m1 = vm.m1
expect(m1(2, 3)).to.equal(5)
})
//檢測數據更新
it('should change correct content', () => {
vm.m2();
//需要等到頁面加載完畢,再去進行數據更改
Vue.nextTick(()=>{
expect(vm.$el.querySelector('.hello h1').textContent)
.to.equal('123')
})
})
//檢測異步方法
it('async m3 should return 6', () => {
vm.m3(2, 4, (num) => {
expect(num).to.equal(6)
})
})
//檢測接口請求
it('api request', () => {
//屏蔽真正的請求
let axiosstub = sinon.stub(axios,'get')
//提供模擬真正請求的數據
let callback = sinon.spy(() => {
return 5
})
const getmes = vm.getmes
const finalData = getmes(callback)
expect(finalData).to.equal(4)
})
})
組件內編寫方法
<script>
import axios from 'axios'
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
methods:{
m1(a,b){
return a+b
},
m2(){
this.msg = 123
},
m3(a, b, cb){//入侵一個cb
setTimeout(()=>{
cb(a + b)
}, 2000)
},
getmes(cb){
axios.get('/aaa/bbb')
let res = cb()
res-=1
return res
}
}
}
</script>
4、npm run unit進行檢測
注意
如果選擇了jest,配置文件裏需要修改,否則無法啓動命令,其他操作相同。