Day 4:TDD-Coverage;強制轉型;變數作用域

Coverage 覆蓋率

「我寫的測試條件夠多了嗎?有每個判斷條件都跑嗎?極端情境有考慮到嗎?」


參數化測試

列舉同一個 function 多組不同輸入輸出一次測試的方法 實際寫的時候感覺很像窮舉法,但又不確定該寫幾組比較適當 所以開始思考評估測試程式碼的方法


Coverage 確認測試程式碼包含功能程式碼所有可能情境的程度

安裝:pnpm i -D @vitest/coverage-v8 (預設值)

遇到相依 Vitest 版本不對齊的提示,強制升版到提示版本號:pnpm up vitest@4.0.13 -D

執行:pnpm vitest run --coverage

產生報表:

post image

顯示 q1.js 的第 8,21 行在測試中沒有踩到

  • 行沒被執行 → 代表「沒有任何一組輸入」讓執行流程走到那一行。

  • Branch 沒滿 → 至少有一個 if / else if / else / case / default 的某個出口沒被走過。例:只有測「valid input」,沒有測「邊界值 / 錯誤 input」,那錯誤處理分支就不會被覆蓋。

可以回頭檢視調整測試程式碼(q1.test.js)和功能程式碼(q1.js):

  1. 確認 q1.js 執行邏輯

  2. 根據執行邏輯反推 q1.test.js 要補的測試條件

  3. 補完後再次執行 pnpm vitest run --coverage確認,以上流程反覆進行

修改完確認測試覆蓋率 100%

post image

目前對 TDD + Coverage 的理解

  • 在 TDD 流程中,檔案大致分工可以是:

    • app.test.js:先寫測試,描述預期行為(紅燈)。

    • app.js:再寫功能邏輯,讓測試通過(綠燈)。

    • main.js:最後由主程式負責把 UI / 事件 / API 等互動,串接到 app.js 的功能邏輯。

  • TDD 的核心循環:

    • 先寫測試(紅燈)。單元測試是針對每個單一功能程式 function 撰寫測試。

    • 寫最小實作讓測試通過(綠燈)。

    • 在測試保護下重構程式碼(重構)。

  • Coverage 在這個流程中的角色:

    • coverage 用來檢查「哪些程式碼路徑在測試中被執行過」,例如行(Lines)、敘述(Statements)、分支(Branches)、函式(Functions)。

    • 透過 coverage 報告可以找出「完全沒被任何測試踩到的邏輯路徑」,幫助判斷目前的測試案例是否還不夠完整,需要補哪些情境(例如錯誤輸入、邊界值、不同布林組合)。

    • coverage 數字高代表「程式有被跑到」,但不代表行為一定正確;測試本身的斷言內容仍然可能寫錯或漏寫,所以 coverage 是輔助指標,不是品質保證書。

補充文件:

進階:突變測試 stryker mutator

一種用抽換功能程式碼邏輯以驗證與改善測試程式碼的方法

已安裝 pnpm 套件,留待之後再練習

官方文件

ToBoolean 轉型學習記錄

今日閱讀:

  • 《008 天重新認識 JavaScript!》第二天

  • 《JavaScript 概念三明治》PART 1 基本語法與概念說明

先記住:falsy 值只有這些

在 JavaScript 裡,ToBoolean 會轉成 false 的值(稱為 falsy)只有以下幾種:

  • undefined

  • null

  • false(布林本身)

  • 數字:+0、-0、NaN

  • 空字串:"" 或 ''

除此之外的所有值,都會被 ToBoolean 轉成 true(稱為 truthy),包括非空字串、物件、陣列、函式、非零數字等等。


!! 的轉型步驟(以練習題為例)

題目:

!!false == !!true

!!false === !!true

兩邊型別一樣(都是 boolean),所以這裡 == 和 === 的結果相同,而且實際比較結果都是 false,因為 false 不等於 true。


關鍵觀念整理

  • ToBoolean 規則:只要記住「那幾個 falsy」,其他全部都是 truthy。

  • !!value 的用途:把任何值強制轉成真正的 boolean,並保留原本的 truthy / falsy 含義。

  • 字串陷阱:不管內容是 "false"、"0"、"no",只要不是空字串,都會被當成 truthy,因此 !!"false"、!!"0" 都是 true。

  • 當兩邊都已經是 boolean 時,== 和 === 行為一樣,但實務與風格上仍建議統一使用 === 以避免混淆。

其他強制轉型的寫法

  • 轉型成字串:String(5), 5+""

  • 轉型成數值:Number("5"), +"5"(一元運算子)

  • 轉型成布林:Boolean(5), !!5

物件強制轉型方法

  • 轉型成字串:obj.toString(), String(obj)

  • 轉型成數值:obj.valueOf(), valueOf(obj)/ Number(obj)

變數作用域與全域汙染

把 function 使用的變數移到 function scope 宣告