測試的意義
測試的目的是保證程式碼品質的下限,沒有測試的程式碼近乎沒有下限。這樣的程式碼往往也會耗費更多時間來定位 bug,也不容易根除問題。
測試主要用來看某段邏輯是否符合預期,例如:
- 輸入的 email 符合格式後才進行已註冊 email 的相關驗證
- 輸入的日期資料沒有符合
'YYYY-MM-DD'就拋出錯誤
這個分類的所有文章皆以 TypeScript 搭配 Vitest 示範。
單元測試
單元測試 (Unit Test) 的規模可以是一個函式、類別、模組,也就是針對小規模的邏輯所做的測試。
所以:規模小 = 容易撰寫 = 最快看到收益
單元測試專注在驗證單一功能的各種情境,因此會將連動的外部模組都使用假資料模擬,提高測試的隔離性。
案例:
- 後端:repository、service 等 CRUD 或資料重組的輸入輸出
- 前端:UI 元件的狀態變化、hooks 的邏輯
整合測試
整合測試 (Integration Test) 通常需要驗證多個模組的交互流程,假資料的模擬會更少。通常是用來測試一些重要的業務邏輯和模組。
案例:
- 後端:API 呼叫 → service → repository → 資料庫的完整流程
- 前端:表單提交 → API 呼叫 → 狀態更新 → UI 渲染
端對端測試
端對端測試 (End to End Test) 會以使用者的角度來驗證完整操作流程。
後端要保證 API 端點的存取流程,前端要模擬使用者的 UI 操作流程。所以嚴格來說,請一個人實際從畫面上操作功能也是一種完整的 E2E 測試(全民公測)。
案例:
- 後端:註冊 → 登入 → 新增 Todo → 查詢的完整 API 流程
- 前端:模擬使用者點擊、輸入、導航的完整操作
覆蓋率
覆蓋率 (Coverage) 是指測試的程式碼執行時涵蓋了多少原始的程式碼,常見指標包括:
- 行覆蓋率:執行過的程式碼行數比例
- 分支覆蓋率:執行過的條件分支比例 (if/else)
- 函式覆蓋率:執行過的函式比例
覆蓋率高 ≠ 測試品質好,重點是測試我們真正需要的情境
起手式
測試區塊
輸出兩數總和:
export function sum(a: number, b: number): number {
return a + b;
}
要測試的功能會使用 describe 包住,稱為測試區塊 (test suite):
describe('sum 函式', () => {
it('1 加 2 應該等於 3', () => {
expect(sum(1, 2)).toBe(3);
});
it('1 加 -1 應該等於 0', () => {
expect(sum(1, -1)).toBe(0);
});
});
測試區塊中會使用 it / test(兩種函式功能相同) 來列舉每一個要測試的情境,稱為測試案例 (test case)。
describe 與 it 的參數結構相同,第一個參數可以輸入文字描述,英文的描述慣例是 should...。
測試的運行結果也會將這段描述打印出來:

3A Pattern
輸出陣列中所有數字的總和:
export function sumArray(arr: number[]): number {
return arr.reduce((acc, curr) => acc + curr, 0);
}
3A 是測試的撰寫慣例:
- Arrange(準備): 設定測試資料
- Act(執行): 呼叫要測試的函數
- Assert(驗證): 檢查結果是否符合預期
測試案例通常都按此結構撰寫:
describe('sumArray 函式', () => {
it('[1, 2, 3] 應該等於 6', () => {
// Arrange
const mockInput = [1, 2, 3];
// Act
const result = sumArray(mockInput);
// Assert
expect(result).toBe(6);
});
});
測試案例需要確保每個案例都要能獨立執行,如果測試之間會互相干擾結果,測試的準確性就不穩定、不真實。
制定測試案例
測試案例不需要窮舉。
測試的目的在於驗證功能行為是否符合預期,而不是在強調每個步驟都要做對,反過來說,先確定這個行為應該造成什麼結果,就會制定出正確的步驟。
例如範例的 sumArray,因為只有一個參數,測試案例只需要:
- 確認這個函式會回傳一個正確加總過的數字
- 傳入空陣列會回傳什麼
- 傳入非陣列的參數會回傳什麼(這會在靜態檢查階段擋下,通常不需要測試這個案例)
小結

標準的測試金字塔會長這樣,這裡可以直覺地去想:
單元 = 顆粒小 = 數量多端對端 = 顆粒大 = 數量小
但這是「標準」狀況,實際開發會歷經不同的階段和突發狀況,調整各種測試的比例,因此有個重要守則:
不要在需求不明確的情況下開始構思測試策略
雖然「越早導入測試越好」是一個良好習慣,但如果是 PoC 這種專案輪廓還沒有成形的階段,會反覆地探索需求、測試可行性與市場價值,功能需求會快速變動,可能過一晚又推翻了,這時候去拚測試的覆蓋率意義不大。還是可以寫,但是先以核心業務邏輯為主。