前端測試


測試

為什么項目需要測試

測試是完善的研發體系中不可或缺的一環,前端同樣需要測試。一個項目最終會經過快速迭代走向以維護為主的狀態,在合理的時機以合適的方式引入自動化能夠讓我們提前發現 bug,此時定位和修復的速度比開發完再被叫去修改 bug 要快許多;在項目重構或者開發人員發生變化也能保障預期功能的實現。

可測試方向

  • 界面回歸測試: 測試界面是否正常,這是前端測試最基礎的環節
  • 功能測試: 測試功能操作是否正常,由於涉及交互,這部分測試比界面測試會更復雜
  • 性能測試: 頁面性能越來越受到關注,並且性能需要在開發過程中持續關注,否則很容易隨着業務迭代而下降
  • 頁面特征檢測: 有些動態區域無法通過界面對比進行測試、也沒有功能上的異常,但可能不符合需求。例如性能測試中移動端大圖素材檢測就是一種特征檢測,另外常見的還有頁面區塊靜態資源是否符合預期等等。

前端測試框架

前端測試工具也和前端的框架一樣紛繁復雜,其中常見的測試工具,大致可分為測試框架、斷言庫、測試覆蓋率工具等幾類。常見的測試框架有JasmineMocha, 以及要介紹的 Jest

測試框架的作用是提供一些方便的語法來描述測試用例,以及對用例進行分組。
測試框架可分為兩種,TDD (測試驅動開發)和 BDD (行為驅動開發)。

前端是一種特殊的GUI軟件.

斷言庫

所謂斷言,即提供語義化的方法,用於對參與測試的值做各種各樣的判斷,如不一致就拋出錯誤。常見的斷言庫有 should.jsChai.js

所有的測試用例(it塊)都應該含有一句或多句的斷言。它是編寫測試用例的關鍵

1
expect(add(1, 1)).to.be.equal(2);

Jest

Jest 內置了常用的測試工具,如斷言、測試覆蓋率。

命名慣例

測試文件有如下常見的命名慣例。

  • __tests__ 目錄下以 .js 為后綴的文件。
  • 以 .test.js(x) 或者 .spec.js(x) 為后綴的文件。

測試文件可以位於項目根目錄下任何位置,可以通過 testMatch 修改默認配置。

編寫測試

Jest 的作用是運行測試腳本。通常,測試腳本與所要測試的源碼腳本同名,但是后綴名為 .test.js。測試腳本可以獨立運行。

測試腳本里包含一個或多個 describe 塊, 每個 describe 里應該包含一個或多個 test 塊。

1
2
3
4
5
6
7
8
9
10
11
12
/* add.js */
function add(x, y) {
return x + y;
}
 
/* add.test.js */
const add = require('./add.js');
describe('加法函數的測試', function() {
it('1 加 1 應該等於 2', function() {
expect(add(1, 1)).toBe(2);
});
});

Jest 提供了內置的全局函數 expect 進行斷言。

describe 稱為測試套件(test suite),表示一組相關的測試。第一個參數是測試套件的名稱,第二個參數是實際執行的函數。

test 稱為測試用例(test case),表示一個單獨的測試,是測試的最小單位。第一個參數是測試用例的名稱,第二個參數是實際執行的函數。

1
2
3
it('work without done', () => {}); // 同步執行
 
it('work with done', (done) => {}); // 觸發異步,執行 done() 通知 Jest 之行完畢

 

異步測試

使用單個參數調用 done, Jest 會等 done 回調函數執行結束后,結束測試。如果 done() 永遠不被調用,這個測試將失敗。

1
2
3
4
5
6
7
8
9
it('works with done', (done) => {
var x = true;
var f = function() {
x = false;
expect(x).toBeFalsy();
done(); // 通知 Jest 測試結束
};
setTimeout(f, 4000);
});

 

Jest 支持使用 Promise, 從測試返回一個 Promise, Jest 會等待這一 Promise resolve。 如果 Promise 被拒絕,則測試將自動失敗。

1
2
3
4
5
6
7
8
9
10
11
12
const requestFn = (name) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('name');
}, 1000);
})
}
 
it('works with promises', () => {
expect.assertions(1); // 當前測試中執行斷言的次數
return requestFn('mxl').then(data => expect(data).toBe('name'));
});

 

Jest 也支持 async/await 語法的測試,無需多余的操作,只要在 await 后進行斷言即可。

可以使用 expect.assertions 來驗證一定數量的斷言被調用,以判斷異步代碼是否如預期一般執行。

測試組件

冒煙測試 驗證一個組件渲染沒有拋出異常,淺渲染並且測試一些輸出,完整渲染測試組件的生命周期和狀態的改變。

1
2
3
4
5
6
7
8
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
 
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});

初始化測試環境

使用 browser API 需要 mock,或者在測試前運行全局的配置,可以在 setup.js 文件里配置。

測試用例鈎子

有時我們想在測試開始之前進行下環境的檢查、或者在測試結束之后作一些清理操作,這就需要對用例進行預處理或后處理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
describe('hooks', function() {
 
beforeAll(function() {
// 在本區塊的所有測試用例之前執行
});
 
afterAll(function() {
// 在本區塊的所有測試用例之后執行
});
 
beforeEach(function() {
// 在本區塊的每個測試用例之前執行
});
 
afterEach(function() {
// 在本區塊的每個測試用例之后執行
});
 
// test cases
});

 

測試用例管理

項目中測試用例很多,但希望只運行其中的幾個,可以用only方法,describe 塊和 test 塊都允許調用 only方法,表示只運行某個測試套件或測試用例。

1
2
it.only('1 加 1 應該等於 2', () => { ... });
fit('1 加 1 應該等於 2', () => { ... });

 

此外,還有 skip 方法,表示跳過指定的測試套件或測試用例。

1
2
it.skip('1 加 1 應該等於 2', () => { ... });
xit('1 加 1 應該等於 2', () => { ... });

覆蓋率報告

Jest 匹配文件生成測試報告,不需要額外的配置。

除了會再終端展示測試覆蓋率情況,還會在項目下生產一個 coverage 目錄。

1
npm test -- --coverage

 

小結

對於一些需求頻繁變更、復用性較低的內容,編寫測試用例得不償失,適合引入測試用例的場景如下:

  • 需要長期維護的項目。它們需要測試來保障代碼可維護性、功能的穩定性
  • 較為穩定的項目、或項目中較為穩定的部分。給它們寫測試用例,維護成本低
  • 被多次復用的部分,比如一些通用組件和庫函數。因為多處復用,更要保障質量

參考文獻

react-test-demo(git上挺好的中文講解)
jest(中文)
jest(英文)
Jest Snapshots and Beyond - React Conf 2017
The Difference Between TDD and BDD


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM