0%

【進階ノ章】寫測試的最佳實踐(Testing Best Practice)

vitest-logo

最佳實踐(Best Practice)

程式語言本身可分為語法(Syntax)與語意(Semantics)兩部分:語法的部分主要受限於語言中的設計以及工具基於這些設計打造了什麼功能供我們使用,而語意的部分則是我們如何透過這些語法,來設計、歸納好我們想表達的邏輯。

同樣地,測試程式碼也是程式碼的一環,在撰寫測試程式碼的時候,我們除了語法上的學習之外,也應當考量測試程式碼的可讀性與維護性等等。

而今天的主題,我們要來一起欣賞開源專案 《JavaScript 測試的最佳實踐》,在這份指南中集結了大量的文章與書籍所給予撰寫測試程式碼上的建議!

由於這份指南說真的沒有很長,個人非常推薦把這個項目的內容完整閱讀一遍,因此本文主要傾向補充說明我個人的看法;並將本系列文提過的概念條列出來,讓讀者可快速回想。

若是英文苦手的開發者朋友們,也可以參考由
YuBin 所翻譯的 中文版本

已經提及過的部分

  • 1.2 3A 模式(Arrange, Act, Assert)
  • 1.4 只測試公開方法 => 只驗證介面上的操作而非私有的方法。
  • 3.2 使用不易改變的屬性來查詢 => 使用 data-* 屬性作為測試選取標準
  • 3.6 基於 FIRST 原則中的 F(Fast) => 遇到會花費時間的測試,應盡可能的縮短時間,比方 request 非同步的資料應考慮使用回傳模擬資料。
  • 4.1 藉由足夠的覆蓋率來獲得信心 => 以 80-90% 的覆蓋率為目標之一。
  • 4.3 使用「變異測試」測量邏輯覆蓋率

補充說明

1.3 BDD 風格斷言

斷言風格主要在 斷言語法 章節中有稍微提到不同風格的問題,筆者個人認為風格問題應回歸到團隊上的使用習慣。

而文中所舉的反例,個人認為比較像是因邏輯上的複雜度導致斷言上的困難,那麼透過拆分測試案例也是一種方式。

e.g.

1
2
3
test('...情況下,應該為 A 且不為 B', () => {
// ... 不論哪種斷言風格
})

可考慮拆解成:

1
2
3
4
5
6
test('...情況下,應該為 A', () => {
// ... 不論哪種斷言風格
})
test('...情況下,不能為 B', () => {
// ... 不論哪種斷言風格
})

此外,Vitest 兼容 Jest 斷言語法,也可以透過 expect().not Matchers 來反轉邏輯,所以解方也有很多種。

1.5 使用正確的測試替身 (Test Double)

測試替身一直是測試中比較困難的部分,因為不同測試替身的使用時機和關注點不太一樣,筆者主要是建議使用測試替身的相關語法前,一定要先思考的一件事情就是斷言目標在誰身上

以下簡稱 Vue Test Utils 為 VTU

  • Stub 類型:單純想避免依賴物回傳的干擾,並斷言受測物反映的結果:VTU => stub, Vitest => vi.stubGlobal, vi.fn
  • Spy 類型:監聽受測物使用這個依賴時做了什麼(呼叫次數、帶的參數):Vitest => vi.fn, vi.spyOn
  • Mock 類型:控制依賴物的一切,連同能用什麼方法(method)都被控制:Vitest => vi.mock

1.8 簡短的行內快照 (inline snapshots)

在先前快照測試中我們有提到 Vitest 中有個 toMatchInlineSnapshot() 語法,會在測試案例中直接生成快照檔,從而避免管理快照檔案上的負擔,但同時也讓測試檔案行數快速膨脹,所以建議用在小範圍的測試,或是使用 data-test 屬性選取到特定的目標範圍後再進行快照。

反串註明:如果公司 KPI 是以產生程式碼行數的話或許可以大幅增加你的績效。

1.11 為測試案例打上標籤

這個做法主要是依賴於測試運行環境時主要有提供 filter 測試案例的功能,筆者覺得有趣但要思考的一點是:設計中有分類設計,就會免不了遇到分類時要如何管理的議題。

如果真的要使用就必須先考量好分類的標準,先例可以參考比方 Github 開源專案中對於 Issue 所做的 Tag 分類,或是 Git 中 Commit 時會用到的 Message 標籤。

1.12 把測試案例進行至少兩個層次的分類

這部分主要是警惕避免將案例描述全合併成一個案例,使其名稱過長,而規模越大的專案就越容易受其影響。

3.3 如果可以,使用真實且完全渲染的組件來進行測試

這一部分筆者認為應考慮進行元件測試時要使用社交型測試風格還是孤立型測試風格。

以孤立型風格來說,目標的關注點將會在於每個元件本身在各種案例下應該會呈現的樣貌,其中用到 Vue Test Utils 中的 shallowMount 不失為一種合理的用法,因為當我們在透過 <-stub> 隔絕底下子元件時,我們主要是希望先關注在受測物(元件本身)所發生的事情。而若想確保與依賴物之間的關係,孤立型測試可再以 mount 來快照子元件的樣貌來保證子元件更改時會通知。

4.4 使用 Test linter 來避免測試程式的問題

基本上主要是有關於設置 ESLint 或 ESLint + Prettier 時有沒有好好設置規則,如先前所提 到 Vitest 也有提供 Config 設定 test.globals 的功能,那麼我們也需要在 .eslintrc.json 通知 ESLint 這個全域變數的存在。

而文中更加強的部分是,要加入有關於給測試時用的 Lint!主要有時可能為了開發上的方便會用到 .skip 語法來跳過某些測試情境或案例,甚至是訂定撰寫案例上的規則,這時候這些給測試專用的 Lint 就非常方便。

但免不了的是,在使用跨開發環境時的功能還是有機會被影響到,比方前面提到 在 Vitest UI 內寫測試時,相關工具會沒辦法引入設定而導致錯誤發生。


以上便是有關於一些撰寫測試案例上有關於最佳實踐的補充說明,再次說到,指南的部分真的沒有很長,非常推薦大家可以花時間閱讀。而隨著大家測試撰寫的越多,你可能也會找到大家未發現過的優良實踐,也歡迎大家踴躍分享自己的經驗!