測試驅動(dòng)開(kāi)發(fā)(Test-Driven Development)是一種軟件開(kāi)發(fā)的思維和方法,我的理解是它是一種開(kāi)發(fā)的循環(huán),先寫(xiě)測試代碼,再用最小的代碼實(shí)現這個(gè)測試,再繼續寫(xiě)測試代碼,繼續用最小的代碼實(shí)現。當實(shí)現所有的測試用例,代碼也就完成了。
最近也在實(shí)踐Tdd開(kāi)發(fā),和之前先開(kāi)發(fā),再自測的方向不同,這次的開(kāi)發(fā)順序是, 文檔--->測試用例--->代碼--->測試通過(guò)--->下一個(gè)測試用例。這樣做有以下優(yōu)缺點(diǎn):
總體來(lái)說(shuō),如果對一些基數設施的建設,比如基礎組件等,需要長(cháng)期維護的項目,Tdd的應用,還是利大于弊。
如果想應用Tdd的方法到前端的開(kāi)發(fā)中,主要用到以下幾個(gè)工具(工具的用法在后面介紹):
mocha 主要提供了describe的語(yǔ)法,用來(lái)描述測試用例,并且把執行測試后的結果清楚的返回到終端上。
官網(wǎng):mochajs.org
github: github.com/mochajs/moc…
chai 主要提供了斷言函數assert,用來(lái)斷言和比較測試的結果和代碼執行的結果。
官網(wǎng):www.chaijs.com/
github: github.com/chaijs/chai
assert庫方法文檔: www.chaijs.com/api/assert/…
sinon 主要用來(lái)mock一些東西,比如可以用sinon mock一個(gè)假的函數,sinon也可以返回這個(gè)函數執行與否。
官網(wǎng):sinonjs.org
github: github.com/sinonjs/
先npm init生成一個(gè)項目。 再執行以下安裝語(yǔ)句:
npm install sinon moncha chai sinon-chai --save-dev
復制代碼
建立一個(gè)test文件夾,可以把寫(xiě)測試用例的Js放在這個(gè)文件夾中, 為了可以方便執行單元測試,可以加一個(gè)npm scripts,在package.json的scripts中加入如下語(yǔ)句,表示使用mocha去執行test文件夾下的js測試:
"scripts":{
"test": "mocha test/**/*.js"
}
復制代碼
在test中建立一個(gè)js文件,在文件的中引入這些工具,為了連接sinon 和 chai,要使用到sinon-chai
const chai = require("chai")
const sinon = require("sinon")
const sinonChai = require("sinon-chai")
chai.use(sinonChai)
const assert = chai.assert // 從chai中引出assert
復制代碼
首先我們看一個(gè)簡(jiǎn)單的單元測試代碼:
describe('測試navigateTo方法', ()=>{
it("new router后存在navigateTo方法", ()=>{
let newRouter = new VictRouter()
assert.isFunction(newRouter.navigateTo)
})
})
復制代碼
直接在describe中加入多個(gè)it函數即可:
describe('測試navigateTo方法',()=>{
it(`new router 后存在navigateTo方法`, ()=> {
let newRouter = new VictRouter()
assert.isFunction(newRouter[key])
})
it(`navigateTo的入參類(lèi)型必須為object`, ()=>{
let newRouter = new VictRouter()
let badFn = function() { throw new newRouter[navigateTo]('1111')}
assert.throws(badFn, 'this.commonDirectFn is not a function')
})
})
復制代碼
npm run test之后可以執行所有的測試
在執行的代碼中,特別在開(kāi)始一些對入參的判斷的代碼,可以使用throw出錯誤,再用assert捕獲這個(gè)錯誤,這樣可以比較方便的測試入參是否符合預期。但是使用assert.throws的時(shí)候,要用一個(gè)函數包裝要測試的代碼:
it(`navigateTo的入參類(lèi)型必須為object`, ()=>{
let newRouter = new VictRouter()
let badFn = function() { throw new newRouter[navigateTo]('1111')} // 這里用一個(gè)函數包裝
assert.throws(badFn, 'this.commonDirectFn is not a function') // 再把包裝后的函數傳入throws
})
復制代碼
如果需要模擬一個(gè)函數,可以用sinon去模擬,使用方法:sinon.fake(),并且課已通過(guò)這個(gè)sinon的called方法判斷函數是否被執行。
let fn = sinon.fake() //生成一個(gè)模擬函數
assert(fn.called) //斷言這個(gè)函數是否被執行
復制代碼
本文只是對Tdd的一個(gè)簡(jiǎn)單介紹,適用于快速入門(mén)。mocha,chai,sinon的一些高級的用法,還需要通過(guò)實(shí)踐去學(xué)習。 另,本文只是對但純js的測試,react,vue和小程序都有他們自己的ui測試的方案。 想通過(guò)本文,讓大家可以簡(jiǎn)單了解Tdd,并且學(xué)到一種新的思路去寫(xiě)代碼。
原文轉自:https://juejin.im/post/5d7710bae51d453bb13b66b0