玩轉 Github Profile Readme:單元測試

Curly_Brackets發表於2021-08-29

這是我參與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

單元測試落地

structure.002.jpeg 現有的模組劃分還是挺清晰的,自底向上開始覆蓋,同時把原專案的測試用例遷移一下。

Screen Shot 2021-08-29 at 10.18.59 AM.png

執行和除錯

在測試過程中需要執行單個或多個用例,或者對某個用例做除錯。藉助 VSCode 外掛輕鬆搞定:

VSCode Jest 更接近於全面的視覺化套件但又無法直接執行新增的測試用例。需要搭配 VSCode Jest Runner 實現完全效果。

對於我來說並不需要自動執行測試,但 coverage、視覺化狀態都是很不錯的功能,手動執行和除錯是硬核需求。因此我的配置是兩個外掛搭配使用 + 關閉 VSCode Jest 的 autoRun 功能。

// settings.json
{
  "jest.autoRun": "off"
}
複製程式碼

Screen Shot 2021-08-25 at 11.13.15 AM.png

這樣一來各層級的執行+除錯都齊了。

遇到的難點

如何測試 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

The Jest Object · Jest (jestjs.io)

curly210102/github-readme-stats at refactor

相關文章