目錄
-
概述
- 為何要寫測試
- 前端測試的類型
- TDD vs BDD
-
常用前端單元測試框架
- Jest
- Mocha
-
More
- 前端測試該寫些什么
- 寫什么都比沒有開始好
- 參考鏈接
概述
為何要寫測試?
從自己的經(jīng)驗來說,在開發(fā)階段,寫測試能幫助自己對功能的實現(xiàn),有一個較為全面的思考,并且降低后續(xù)修改引入 Bug 的幾率。在交付之前,就能排除大量的 Bug。在后續(xù)測試,或需求變更的情況下,修改代碼之后,可以保證不對已經(jīng)穩(wěn)定的功能引入新 Bug。從別人處接手項目時,也能大大避免因新接手人員對項目不熟悉,引入的新問題。
總體上來說,為自己的代碼寫測試,是一項首次繁瑣、后續(xù)便利的工作,并且從長遠來看,一個項目后續(xù)修改的頻率要遠遠大于首次的構建和開發(fā),不論對測試、開發(fā)、交接都是利大于弊的╮(╯_╰)╭。
這篇以本人入手時的體驗,簡單介紹前端測試的部分內(nèi)容。
前端測試的類型
有一種關于測試的分類,稱為前端測試金字塔,將前端測試從塔底到塔尖分為:
- 單元測試(Unit Tests)
顧名思義,對一個功能單元進行測試,如一個對日期進行格式化的方法。
單元測試是非常細化和相對全面的,要保證一個單元代碼的可靠性,需要盡可能地對所有情況編寫測試腳本。 - 快照測試(Snapshot Tests)
快照測試是對 UI 組件渲染結果的測試。
在 Jest 中,快照測試并不是對圖片進行比對,而是保存渲染組件的標記,使得快照文件體積小,而測試速度快。
更多關于 Jest snapshot test - 端到端測試(End to End Tests)
是對模擬我們對項目的實際操作,測試過程較為復雜和繁瑣,耗時長。
想了解更多關于這幾種測試類型的細節(jié),請看 前端測試金字塔
TDD vs BDD
測試驅動開發(fā)(TDD)是先寫測試,根據(jù)測試的內(nèi)容實現(xiàn)具體的功能代碼,再用之前的測試進行驗證。TDD 是用測試來推動功能的實現(xiàn)。
行為驅動開發(fā)(BDD)是從行為的角度來定義測試的內(nèi)容,用自然語言描述測試用例。
有關于 TDD 和 BDD 的思考,可以參考 The Difference Between TDD and BDD
常用前端單元測試框架
常見的測試框架有 Jest,Mocha,Jasmine 等。
這里舉例說明一下 Jest 和 Mocha。
Jest
- 配置簡單(開箱即用)
- 自帶斷言庫(在 Jest 中稱為 matchers)
- 內(nèi)置的覆蓋率(coverage)統(tǒng)計
- 內(nèi)置的快照功能
Jest 由 Facebook 團隊開發(fā)維護,故對于測試 React、ReactNative 項目支持友好。
使用
(來自官網(wǎng)的例子)
新建一個項目(npm init),新建一個 /src 目錄和 /test 目錄,用于存放功能代碼和測試代碼。
安裝 Jest,無需額外配置:
npm install --save-dev jest
// or
yarn add --dev jest
完成后的目錄如下:
/project
-/node_modules
-/src
-/test
在 /src 文件目錄下新建一個 sum.js 文件,
function sum(a, b) {
return a + b;
}
module.exports = sum;
在 /test 中新建一個 sum.test.js 文件,引入 sum.js 的方法:
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
在 package.json 的 scripts 中新增:
"scripts": {
"test": "jest"
}
之后運行:
npm run test
// or
yarn test
就可以得到結果:
PASS ./sum.test.js
? adds 1 + 2 to equal 3 (5ms)
上面例子中的“expect(sum(1, 2))”稱為斷言,在 Jest 中叫做“matchers”,Jest 提供了多種 API 滿足不同的情況。
Jest 為每個測試文件預置了一些全局方法和對象,“test” 用來包裹一個最小的測試單元,一系列相關的測試單元可以用 “describe”包裹:
const myBeverage = {
delicious: true,
sour: false,
};
describe('my beverage', () => {
test('is delicious', () => {
expect(myBeverage.delicious).toBeTruthy();
});
test('is not sour', () => {
expect(myBeverage.sour).toBeFalsy();
});
});
Mocha
- 配置自由靈活
- 自行引入需要的斷言庫
- 支持幾種不同的測試代碼的組織形式(包括 BDD、TDD 等)
- 可運行在 Node 環(huán)境和瀏覽器
Mocha 的有更高的自由度,更能配合需要高度定制化的項目,插件配置方面也能找到大量的參考信息。
使用
安裝方式類似。
Mocha 需要自行引入斷言庫(即需要自行額外安裝對應的庫),在使用上,和 Jest 并沒有太大區(qū)別:
var assert = require('assert')
describe('Array', function() {
describe('#indexOf()', function() {
it('should return -1 when the value is not present', function() {
assert.equal([1,2,3].indexOf(4), -1)
})
})
})
可以直接運行:
./node_modules/mocha/bin/mocha
或者也在 package.json 中新增 scripts:
"scripts": {
"test": "mocha"
}
...
npm test
Mocha 中 describe 是作為 BDD 的一種接口,它同時提供適用 TDD 的接口:suite(), test(), suiteSetup(), suiteTeardown(), setup(), and teardown()等:
suite('Array', function() {
setup(function() {
// ...
});
suite('#indexOf()', function() {
test('should return -1 when not present', function() {
assert.equal(-1, [1,2,3].indexOf(4));
});
});
});
除了 BDD、TDD,Mocha 還支持 Exports,QUnit,和 Require-style 接口,具體參考文檔
More
前端測試該寫些什么
剛開始接觸入門前端測試時,最困擾我的就是測試到底該寫什么了。
對 UI 進行測試的目的較為明確,只要根據(jù)頁面需要達到的效果,對照著加入測試即可。但若進行單元測試,或者針對功能進行測試時,我們總是希望覆蓋面能廣一點、考慮的情況能全面一點,以達到更好的測試效果。不同的項目代碼的功能、組織方式大相徑庭,很難有一套通用的定論來指明我們的測試代碼具體應該怎么寫,但一些思考角度是可以分享和借鑒的。
以下是我針對一個功能型(或者說工具型)項目進行測試的幾個方面:
- 明確的功能點
即需求方給的明確的需求,以及為了實現(xiàn)這些需求,需要達到的一些標準。 - 輸入值、輸出值、邊緣數(shù)據(jù)校驗(特別是工具類型的單元)
如輸入值不符合標準的情況,輸入值不符合標準的情況也可能存在多種情形,都需要分情況考慮。 - 測試過程中出現(xiàn) Bug 的情況
即使在開發(fā)過程中通過測試規(guī)避了很多問題,但不可避免仍會有一些特定場景會引出 Bug,功能修復后添加針對該場景的測試腳本,可以規(guī)避該場景 Bug 的重復出現(xiàn)。
寫什么都比沒有開始好
對于不同的項目,需要側重的測試方面也大不相同,真正開始思考如何全面地測試一個項目,并且轉換成測試代碼之后,能大大提升代碼質(zhì)量,提升代碼的復用性、模塊化劃分、全面性。
從長遠上來看也能顯著提升大型項目的開發(fā)效率,特別是參與開發(fā)人員多、交接頻繁、迭代頻率高的項目。
Thanks.