金凱 周雨
1. 冰辰網絡科技(上海)有限公司 上海 201600;2. 南通駿星信息科技有限公司 江蘇 南通 226500
隨著前端技術的快速發展,多種前端框架占據了前端開發的主導地位,很多邏輯都可以在前端完成,客觀上對前端單元測試提出了新要求。前端單元測試是單元測試的一個分支,具有單元測試的共性,但又具有自己的一些獨特特點。Jest庫作為一個優秀的前端測試框架,較好地實現了前端單元測試。
單元測試[1]是針對程序單元(軟件設計的最小單位)來進行正確性檢驗的測試工作,程序單元是應用的最小可測試部件,通常是函數、過程、方法等。
單元測試框架有很多,但使用方法大同小異,測試時,首先建立一個虛擬上下文環境,用來模擬真實的業務場景,并注入一些公用的參數,隨后,對每個待測函數建立測試,用命令啟動這些測試,用斷言來輸出測試結果。
前端單元測試框架是單元測試框架的一種,使用方法與上文類似,但是,前端單元測試具有一些獨特的性質,首先,前端單元測試框架建立的上下文環境是一個虛擬的瀏覽器環境,在這個環境中可以對DOM結點進行操作。其次,前端單元測試框架可以測試以下幾種特殊的待測單元:①測試前端某個函數的輸出值是否符合斷言;②測試組件渲染出來的HTML頁面某個DOM結點是否符合斷言;③測試前端某個事件是否能被觸發;④測試后臺接口調用是否正確;⑤能進行快照測試,即將頁面的DOM結構存在文件里,下次測試時與其比較,可以實現測試自動化。
Jest是一個Javascript測試框架,由Facebook開源,致力于簡化測試,降低前端測試成本。Jest主打開箱即用、快照功能、獨立并行測試以及良好的文檔和Api。其主要特色有如下幾點。
匹配器:通過匹配實現斷言。
AOP[2]機制:在測試函數啟動前和結束前提供鉤子函數創建測試用的上下文環境,如虛擬數據等。
Mock[3]函數:可以在虛擬上下文創建Mock函數,代替待測函數中的回調函數,用來測試事件的響應。
Jest可以實現對多種前端框架的測試,例如Vue、React等。
單元測試的方法論有TDD(測試驅動開發)和BDD(行為驅動開發)兩種,TDD適合軟件編寫人員兼任測試人員的情況,要點是在開發之前,先寫測試,用測試來定義程序的預期行為,這樣,最后開發的程序一定是能通過測試的程序,也就是符合預期行為的程序。BDD適用于軟件編寫人員與測試人員不是同一人的情況,要點是開發人員要與客戶深入溝通,從具體的業務場景描述軟件行為。
2.2.1 單元測試應該無依賴和隔離。通常在單元測試中,把系統的依賴組件提取出來,用測試替身(Test Double)取而代之,把測試的目標放在測試單元本身而不是單元與組件的交互上。
2.2.2 單元測試是用例自動驗證的,不能依賴人工驗證。在真實的測試項目中,經常會出現程序每次運行時結果都不一樣的情況,例如:從后臺獲取的數據和時間有關,而具體的規律并不清楚,因此運行結果的正確性很難用程序判定,相反的,人工驗證倒是能夠判定運行結果的正確性。
一個具體的Jest測試程序使用了3個重要函數:
describe:組織各個測試,在describe中調用了各個測試,并可對創建測試共有的上下文環境;
it:測試函數本身,在該函數中可以從上下文環境中獲取相關信息供測試使用;
expect,用來實現斷言,從而得到測試結果。
因此,Jest單元測試的一般流程即為:在describe函數里建立一個上下文環境,該環境竟包含了待測函數運行的必要信息,且所有信息都是確定的、可控的。在it函數里將待測函數引入環境使用expect函數設定測試參數和期望結果,建立測試。
Jest單元測試框架可以測試多種場景,下面舉例說明。
首先給出待測函數例子:
需要測試該函數的正確性。
函數很簡單,求兩個數的乘積,對這個函數,可以建立測試用來檢查結果是否正確:
這里用expect函數以函數f的返回值作為參數,toBe函數以期望的結果作為參數,如果兩者相等,則匹配成功。toBe就是一種匹配器,Jest提供了多種匹配器,可以實現不同的匹配方案。
首先給出待測試的Vue組件CustomCard代碼:
需要測試出渲染出的頁面類為“dd”的標簽文本是否為“test”。
測試程序的主要代碼如下:
該測試程序使用find方法抓取DOM,參數可以是css選擇器,也可以是Vue組件的name
首先給出待測試的Vue組件CustomCard代碼:
該組件中定義了一個事件action-btn:clicked,當點擊組件時觸發,現在要測試點擊組件時是否觸發了事件。
測試的主要代碼如下:
這里創建了一個mock函數 event = jest.fn()作為觸發事件后的回調函數,fn函數可以是空函數,僅用來測試是否被調用,也可以加入代碼邏輯,當事件被觸發后進行一些別的測試。
前端調用后臺接口是異步的,通常包裝成promise函數,因此測試用例也是異步的,下面是一個例子:
待測函數:
該函數向遠程服務器發送請求,請求參數為id=1,預期返回函數為字符串”ok”,則測試函數為:
可以看出,這個測試的寫法和測試普通函數類似,但是其中用到了async/await關鍵字,這兩個關鍵字在javascript中是處理異步的標準方案。
快照測試的流程是:當測試程序第一次啟動時,測試把組件渲染成html文件后存放在本地,稱為快照;測試程序再次啟動時,將新生成的html文件與快照文件比較,如果有差別,則測試失敗。由此實現了對UI組件沒有發生非預期的更改的測試。