長期以來,前端測試並不是開發者必須要編寫的,但隨著前端工程化的發展,前端測試已經成為持續整合中重要的組成部分,編寫前端測試可以達到以下目的:
- 正確性:可以驗證程式碼的正確性,在上線前心裡有底。
- 自動化:通過編寫測試用例,可以做到一次編寫,多次執行。
- 解釋性:測試用例中會設計如何使用這些 API,良好的測試用例比開發文件更直觀。
- 驅動開發:要保證程式碼的可測試性,就需要在開發中注意 API 的設計。TDD 測試驅動開發的思想就是在開發階段編寫可測試性程式碼,以保證程式碼的可測試性。
- 保證重構:網際網路行業產品迭代速度很快,迭代後必然存在程式碼重構的過程,那怎麼才能保證重構後程式碼的質量呢?有測試用例做後盾,就可以大膽的進行重構。
單元測試
單元測試包括:斷言,測試框架,測試用例,測試覆蓋率,mock 等幾個方面。目的是讓開發者明確知道程式碼結果。
斷言
斷言:保證最小單元是否正常執行檢測方法。
測試框架
測試框架用於為測試服務,它本身並不參與測試,主要用於管理測試用例和生成測試報告,提升測試用例的開發速度、可讀性和可維護性。常見的測試框架有:mocha,jest,jasmine 等。
測試風格
通常有以下兩種測試風格,開發者可以根據情況選擇。
- 測試驅動開發(TDD):關注所有的功能是否被實現,每一個功能都具備對應的測試用例。
- 行為驅動開發(BDD):關注整體行為是否符合預期,編寫的每一行程式碼都有目的提供一個全面的測試用例集。
TDD 執行流程
TDD(Test Drived Develop)。TDD 的原理是在開發功能程式碼之前,先編寫單元測試用例程式碼,通過測試來推動整個開發的進行。
- setup(單個測試用例開始之前)
- suiteSetup(每一個測試用例開始之前)
- test(定義測試用例,並用斷言庫進行設定)
- teardown(單個測試用例開始之後)
- suiteTeardown(每一個測試用例開始之後)
suite('Array', function() {
setup(function() {
// 測試用例開始之前
});
suite('#indexOf', function() {
test('should return -1 when not present', function() {
assert.equal(-1, [1, 2, 3].indexOf(4));
});
});
teardown(function() {
// 測試用例之後
});
});
複製程式碼
BDD 執行流程
BDD(Behavior Driven Development)。行為驅動的開發,描述了軟體的行為過程,可以直接作為軟體的需求文件。
- before(單個測試用例開始之前)
- beforeEach(每一個測試用例開始之前)
- it(定義測試用例,並用斷言庫進行設定)
- after(單個測試用例開始之後)
- afterEach(每一個測試用例開始之後)
describe('Array', function() {
before(function() {
// 測試用例開始之前
});
describe('#indexOf', function() {
it('should return -1 when not present', function() {
[1, 2, 3].indexOf(4).should.equal(-1);
});
});
});
複製程式碼
測試用例
測試用例(Test Case)是為某個特殊目標而編制的一組測試輸入、執行條件以及預期結果,用來判斷一個程式碼功能是否滿足特定需求。測試用例最小需要通過正向測試和反向測試來保證對功能的覆蓋。
使用 it 來定義一個測試用例:
it('should return -1 when not present', function(done) {
// xxx
});
複製程式碼
非同步測試
在執行非同步測試用例時,會將 done 函式注入實參。
it('should return -1 when not present', function(done) {
setTimeout(() => {
done();
}, 1000);
});
複製程式碼
測試覆蓋率
測試覆蓋率用來判斷單元測試對程式碼的覆蓋情況。原理是通過向原始碼中注入統計程式碼,用於監聽每一行程式碼的執行情況。可以統計到該行程式碼是否執行和執行次數。測試覆蓋率包括以下幾個方面:
- 行覆蓋率(line coverage):是否每一行都執行了?
- 函式覆蓋率(function coverage):是否每個函式都呼叫了?
- 分支覆蓋率(branch coverage):是否每個 if 程式碼塊都執行了?
- 語句覆蓋率(statement coverage):是否每個語句都執行了?
E2E 測試
E2E(End To End)測試是模擬使用者進行頁面操作,通過來判斷頁面狀態的變化,從而檢查功能是否執行正常的測試方法。
在使用 E2E 測試時,測試程式常常會自動開啟瀏覽器,執行配置的操作,因此需要驅動瀏覽器,常見的庫有:
- selenium/webdriver
- nightwatch
- puppeteer
效能測試
效能測試的範疇比較廣泛,包括基準測試、壓力測試等。
基準測試
基準測試統計的是在多少時間內執行了多少次某個方法。常用 Benchmark 庫來編寫。
- 面向切面程式設計(AOP)無侵入式統計。
- Benchmark 基準測試方法,他並不是簡單地統計執行多少次測試程式碼後對比時間,它對測試有著嚴密的抽樣過程,執行多少次取決於取樣到的資料能否完成統計。根據統計次數計算方差。
var suite = new Benchmark.Suite();
// add tests
suite
.add('RegExp#test', function() {
/o/.test('Hello World!');
})
.add('String#indexOf', function() {
'Hello World!'.indexOf('o') > -1;
})
// add listeners
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
// run async
.run({ async: true });
// logs:
// => RegExp#test x 4,161,532 +-0.99% (59 cycles)
// => String#indexOf x 6,139,623 +-1.00% (131 cycles)
// => Fastest is String#indexOf
複製程式碼
壓力測試
壓力測試主要是針對於伺服器端,它可以幫助我們發現系統中的瓶頸問題,減少釋出到生產環境後出問題的機率。還能預估系統的承載能力,使我們能根據其做出一些應對措施。
對網路介面做壓力測試需要檢查的幾個常用指標有吞吐率,響應時間和併發數,這些指標反映了伺服器併發處理能力。
- pv 網站當日訪問人數。
- uv 獨立訪問人數。
- qps 伺服器每秒處理請求數。qps=pv/t。
常用的壓力測試工具:ab、JMeter。
安全測試
安全測試是比較專業的測試,測試人員需要了解常見的 web 攻擊方式,然後模擬攻擊測試的程式,以防上線後其他不法人員使用同樣的方式對程式進行攻擊。前端常見的攻擊方式有:
- XSS
- SQL 注入
- CSRF
功能測試
功能測試是對產品的各功能進行驗證,根據功能測試用例,逐項測試,檢查產品是否達到使用者要求的功能。常見的功能測試方法有冒煙測試、迴歸測試等。
冒煙測試
自由測試的一種,找到一個 bug 然後修復,然後專門針對此 bug。優缺點如下:
- 節省時間。
- 缺點覆蓋率極低。
迴歸測試
修改一處對整體功能全部測試,一般配合自動化測試。優缺點如下:
- 大幅度降低出錯概率。
- 時間耗費重。
測試相關庫
- karma:使用真實的瀏覽器環境,並且可測試相容性。
- mocha:測試框架。
- chai:斷言庫。
- istanbuljs/nyc:覆蓋率庫。
- backstopjs:測試 UI。
- benchmark:基準測試。
- phantomjs:無頭瀏覽器。
- nightwatch:e2e 測試。
- jest:大而全。
更多文章,歡迎 Star 和 訂閱我的部落格。