這是我參與8月更文挑戰的第6天,活動詳情檢視:8月更文挑戰
在 Github Profile Readme 使用篇 之後,開始嘗試 github-readme-stats 專案的開發,目標是
- 在 github-readme-stats 專案的基礎上實現一個 Leetcode 統計卡片
- 嘗試搭建一個更易擴充套件的 SVG 生成系統,探索能否直接應用已有的圖表元件。
- 造一個 Profile Readme 視覺化生成器
話說上回,加入 TypeScript 完成了專案邏輯抽象方面的重構。原專案帶著單元測試,想著遷移通過就行卻發現還是需要改進一下。
這一篇文章記錄覆蓋單元測試的過程。
支援 TypeScript
專案原始碼已經遷移到 TypeScript,如何讓 Jest 支援 TypeScript 成為第一個急需解決的問題。
Jest 內建 Babel 7,只需要通過 @babel/preset-typescript 給 Babel 加上編譯 TypeScript 的能力。Babel 只進行編譯,並不會進行型別檢查和宣告檔案生成,如果要在單測時進行型別檢查,需要另起一個 tsc
命令或者使用 jest-runner-tsc: ?A Jest runner for the TypeScript compiler (github.com) 整合進 Jest 執行過程。
// babel.config.js
module.exports = {
presets: [
["@babel/preset-env", { targets: { node: "current" } }], // ES -> NodeJS
"@babel/preset-typescript", // TS -> ES
],
};
複製程式碼
設計單元測試用例
Behavior-driven Test, Test-driven Development! 行為驅動測試,測試驅動開發!
單元測試的本質是針對功能單一的 “單元” 進行測試。如果一份專案程式碼無法進行單元測試,說明程式碼邏輯不夠“單元化”,即一個類或函式的意圖並不明確職責不夠單一。在單元測試設計的過程中往往能發現開發中存在的問題。
一般使用「基本路徑覆蓋」來設計測試用例,再以測試工具的覆蓋率為準,按需對測試用例進行細化。
基本路徑覆蓋的步驟:根據程式碼畫出程式控制流 -> 計算程式環路複雜度 -> 匯出可執行路徑 -> 設計測試用例。
通過基本路徑覆蓋法從一個函式設計出幾個測試用例。單個測試用例需要包含:名稱、輸入、步驟、預期結果,在書寫測試用例程式碼前可以使用表格梳理。
測試用例名稱對應測試目的,即 xx 行為應該出現 yy 結果,套用 "should ... when ..." 的句式;比如密碼為空時返回 false, 命名為 "should return false when password is empty"。
Jest 中的層級概念:
- Suite:單個測試檔案,可以對應單個模組;
- Describe:相關聯的一組測試用例,例如模組中的一個函式產生的多個測試用例;
- Test:單個測試用例,又名 it
單元測試落地
現有的模組劃分還是挺清晰的,自底向上開始覆蓋,同時把原專案的測試用例遷移一下。
執行和除錯
在測試過程中需要執行單個或多個用例,或者對某個用例做除錯。藉助 VSCode 外掛輕鬆搞定:
- Jest - Visual Studio Marketplace 監聽並自動執行測試、提供 coverage、測試狀態視覺化、執行/除錯指定測試(和Jest Runner 重合)
- Jest Runner - Visual Studio Marketplace 執行或除錯指定測試(單個用例、單個Suite、單個檔案)
VSCode Jest 更接近於全面的視覺化套件但又無法直接執行新增的測試用例。需要搭配 VSCode Jest Runner 實現完全效果。
對於我來說並不需要自動執行測試,但 coverage、視覺化狀態都是很不錯的功能,手動執行和除錯是硬核需求。因此我的配置是兩個外掛搭配使用 + 關閉 VSCode Jest 的 autoRun 功能。
// settings.json
{
"jest.autoRun": "off"
}
複製程式碼
這樣一來各層級的執行+除錯都齊了。
遇到的難點
如何測試 private/protected 成員?
類中無需被外部呼叫的成員設定為 private/protected 訪問許可權,保證封裝性。這些私有成員在公有方法中被呼叫,對外的聯絡渠道也就只有這些公有方法。從程式設計角度看,這是合理的。
但是從單元測試的角度出發,「獨立測試這些私有成員」是不成立的。一種直接的解決方式是修改訪問許可權。
當然對於前端體系來說並不存在嚴格的靜態型別,TS 只是在 JS 之上提供了靜態型別系統,訪問許可權只是編碼約束,轉譯為 JS 之後成員並無訪問許可權限制。在測試中可以利用這一點越界訪問。
如果既不想修改訪問許可權,又不想無視訪問許可權,還有一種方式是通過 jest.spyOn
監聽例項方法。
const card = new Card(req.query);
const spy = jest.spyOn(card, "renderCard");
// 呼叫公有方法
await card.generateSvgString(res.setHeader);
expect(spy).toBeCalledWith();
expect(spy).toHaveReturnedWith();
spy.mockRestore();
複製程式碼
下一步
覆蓋單元測試之後,邏輯重構部分完整結束。接下來開始著手 svg 構建部分的程式碼。
專案倉庫:curly210102/github-readme-stats at refactor
Reference
Jest 24: ? Refreshing, Polished, TypeScript-friendly · Jest (jestjs.io)
TypeScript: Documentation - Using Babel with TypeScript (typescriptlang.org)
軟體測試精品教程,深入學習白盒測試設計方法【黑馬程式設計師出品】_嗶哩嗶哩_bilibili