March 11, 2025

前端測試指南 - 策略與實踐 (Chapter 2-1 ~ 2-3)


單元測試

單測著重在「最小單位的測試」與「獨立測試特定的程式碼片段, 確保能獨立運作並正確處理特定情境輸入與輸出


// addNumbers.js
const addNumbers = (a, b) => Number((a + b).toFixed(1))

// addNumbers.test.js
it('should return 0.3 when 0.1 + 0.2', () => {
  expect(addNumbers(0.1, 0.2)).toBe(0.3)
})

作為最小粒度測試, 但是也會有極端或是非實際使用者的意外狀況產生, 因此配合整合測試/端對端測試才可以更好的補足缺漏的地方, 提高測試覆蓋.


Jest

toBe()          // shallow comparison
toEqual()       // deep comparison
toStrictEqual() // *稀疏陣列 / undefined 與 物件 kv => 是更嚴格檢查

toBeNull()      // 比對 null
=> toBe(null)
toBeUndefined() // 比對 undefined
=> toBe(undefined)

*稀疏陣列: [,,,,,,1,] 只存一個 1, 其他都是 null


Enzyme vs React Testing Library (RTL) 差異比較 可以另外看一篇

前端測試指南 - 策略與實踐 (Chapter 2)

但不外乎都是抓測試元件某個按鈕的屬性

// in <component>.js
<button data-test-id="increment-button" ...> + </button>

// in <component>.test.js
>> Enzyme 
wrapper.find('[data-test-id="increment-button"]', () => {...})

>> RTL (RTL 預設 data-testId, 筆者有額外配成 data-test-id)
fireEvent.click(getByTestId("increment-button"))                             

Cypress (反正就只是介紹而已…)


最小範圍的驗證邏輯

要做到最小範圍驗證邏輯必須注意兩個原則:

  1. 檢視測試區塊, 是否只完成一件任務: 功能太多太雜, 需要先分離 (單一職責模式)
  2. 隔絕依賴: 撰寫時需隔絕依賴, 只測試單一功能

例子

const checkValentinesDay = () => {
  const today = new Date()
  const month = today.getMonth() + 1
  const day = today.getDate()
  return month === 2 && day === 14 ? "情人節快樂" : "今天不是情人節"
}

checkValentinesDay 包含以下功能:

因此將職責進行拆分如下

const checkValentinesDay = () => {
  const today = getToday()
  return today === '2/14' ? "情人節快樂" : "今天不是情人節"
}

const getToday = () => {
  const today = new Date()
  const month = today.getMonth() + 1
  const day = today.getDate()
  return `${month}/${day}`
}

隔絕依賴

先對 getToday 進行模擬, 接續進行測試

[!IMPORTANT]

  • 將複雜的程式碼分解成多個部分,確保這些部分與外部依賴隔離
  • 專注於驗證邏輯的最小範圍

jest.mock 什麼時候該用?

不適合用 jest.mock 的情境

如果你的目的是:

那就不該 mock,因為這些測試的目標是 「測 API 是否正常運作」


適合用 jest.mock 的情境

如果你的目的是:

這時候才需要 mock,因為這種測試的目標是 「測你的程式邏輯是否正確」,而不是測 API。