Node.js Jest 單元測試:打造高品質與高穩定性的程式碼
「如果它沒經過測試,它就是壞的」。在大型專案中,測試是防止退化(Regression)並確保重構安全的唯一防線。Jest 是 Node.js 生態系中最全面且零配置(Zero-config)的測試框架,整合了斷言、Mocking 與代碼覆蓋率等功能。
安裝與環境建立
首先將 Jest 安裝為開發依賴:
npm install --save-dev jest
在 package.json 中配置測試腳本,以便使用 npm test 啟動:
"scripts": {
"test": "jest",
"test:watch": "jest --watchAll"
}
撰寫第一個單元測試
假設你有一個待測函式 utils.js:
// utils.js
function calculateTotal(price, quantity) {
return price * quantity;
}
module.exports = { calculateTotal };
建立對應的測試檔案 utils.test.js:
const { calculateTotal } = require('./utils');
// 使用 test 或 it 定義測試案例
test('計算總價:數量 2 * 單價 10 應該等於 20', () => {
// 斷言 (Assertion)
expect(calculateTotal(10, 2)).toBe(20);
});
常用的 Matchers (比對器)
Jest 提供豐富的方法來驗證結果是否符合預期:
toBe():精確相等(比對基礎型別)。toEqual():內容相等(遞迴比對物件或陣列的內容)。toContain():檢查陣列是否包含特定項。toMatch():使用正規表達式檢查字串。toThrow():檢查函式是否正確拋出異常。
測試非同步程式碼 (Async/Await)
這是 Node.js 開發中最常見的場景。Jest 對 Promise 提供了完美的支援。
test('非同步獲取使用者資料', async () => {
const data = await fetchUser(1);
expect(data.name).toBe('Mike');
});
// 或者測試 Promise 的拒絕 (Reject)
test('測試請求失敗', async () => {
await expect(fetchUser(-1)).rejects.toThrow('User not found');
});
Mocking:模擬外部依賴
有時候我們只想測試邏輯,而不希望真的去讀取資料庫或發送網路請求。這時可以使用 Mock。
const db = require('./db');
jest.mock('./db'); // 自動模擬整個模組
test('模擬資料庫查詢', async () => {
// 強制讓 db.find 回傳我們指定的資料
db.find.mockResolvedValue([{ id: 1, name: 'Test User' }]);
const results = await userService.getAll();
expect(results[0].name).toBe('Test User');
expect(db.find).toHaveBeenCalled(); // 確認資料庫方法確實有被呼叫
});
代碼覆蓋率 (Code Coverage)
想知道你的測試漏掉了哪些標記嗎?執行:
npx jest --coverage
這會產出一份詳盡的報表,顯示你的程式碼有多少百分比已被測試覆蓋。
總結
- Jest 讓撰寫測試變得像寫普通程式一樣直覺。
- 善用 Mocking 隔離外部環境,讓你的單元測試跑得又快又穩定。
- 把測試當作 「一份活的技術文件」,它會告訴新加入的成員你的程式該如何正確運作。