在現在的前端應用程式開發中,撰寫測試對於確保代碼的穩定性和可維護性非常重要。而 Jest 就是盛行的其中一個 JavaScript 測試框架,內建支援斷言庫和模擬功能,適合撰寫單元測試、端對端測試等。因為 TypeScript 結合 Jest,可以為我們的測試代碼提供型別檢查,進一步避免潛在的錯誤。
在今天的文章中,我將介紹如何使用 TypeScript 與 Jest 撰寫測試,並提供一些簡單範例來展示實際應用。
在開始撰寫測試之前,需要安裝相關的依賴項。
npm install --save-dev jest ts-jest @types/jest
可以在 package.json
中加入一個 Jest 的配置部分,或建立一個單獨的 jest.config.ts 文件。今天就後者來舉例:
jest.config.ts 設定檔: 主要用來告訴 Jest 如何處理 TypeScript 檔案,並設定測試的執行環境。
export default {
preset: 'ts-jest',
testEnvironment: 'node', // 或 'jsdom',視應用環境而定
moduleFileExtensions: ['ts', 'js'],
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest', // 將 TypeScript 檔案轉換為 JavaScript
},
};
為簡易展示,今天從撰寫一個簡單的 TypeScript 函數測試開始吧!假設我們有一個基本的 add 函數,它的功能是將兩個數字相加:
add.ts:
export function add(x: number, y: number): number {
return x + y;
}
add.test.ts: 為這個 add 函數撰寫測試。
import { add } from './add';
test('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
test('adds -1 + 1 to equal 0', () => {
expect(add(-1, 1)).toBe(0);
});
上面這段程式碼使用了 Jest 提供的 test
函數來定義測試案例,並使用 expect
來斷言結果是否符合預期。
npx jest
添加下列這段到 package.json
的 scripts 區塊中,這樣就可以簡單使用 npm test
指令來執行測試。
{
"scripts": {
"test": "jest"
}
}
運行結果應該顯示所有測試通過,並且 Jest 會顯示測試的執行時間和每個測試案例的結果。
很多時候,我們會有處理一些異步操作的情形,例如 API 請求或資料庫查詢。在撰寫異步函數測試時,可以利用 Jest 的異步支援。
假設我們有一個 fetchData
函數,它模擬從伺服器獲取資料。
fetchData.ts:
export function fetchData(): Promise<string> {
return new Promise((resolve) => {
setTimeout(() => {
resolve('data from server');
}, 3000);
});
}
這是一個模擬的非同步函數,返回一個 Promise,並在 3 秒後 resolve。
fetchData.test.ts:
import { fetchData } from './fetchData';
test('fetches data from server', async () => {
const data = await fetchData();
expect(data).toBe('data from server');
});
在這個範例中,使用了 async/await
來處理異步操作。而 Jest 自動支援異步測試,因此我們只需在測試函數中使用 async 即可。
如果函數拋出異常,可以使用 toThrow
來檢查是否正確地捕捉到錯誤。例如,假設我們有一個會拋出異常的函數:
divide.ts:
export function divide(a: number, b: number): number {
if (b === 0) {
throw new Error('Cannot divide by zero');
}
return a / b;
}
divide.test.ts:
import { divide } from './divide';
test('throws error when dividing by zero', () => {
expect(() => divide(1, 0)).toThrow('Cannot divide by zero');
});
在這個範例中,我們使用 toThrow
來檢查是否會拋出指定的錯誤訊息。
Jest 還有提供了模擬函數的功能,這在不想直接測試副作用(例如 API 請求)時特別有用!假設我們有一個函數依賴於外部的 API,但在測試中我們不希望實際發出網路請求,可以使用 jest.mock
來模擬該函數。
模擬範例:假設我們有一個 getUser
函數,它使用 fetch API 來獲取使用者資料:
api.ts:
export async function getUser(userId: string): Promise<{ id: string; name: string }> {
const response = await fetch(`/users/${userId}`);
return await response.json();
}
api.test.ts:
import { getUser } from './api';
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ id: '1', name: 'John Doe' }),
})
) as jest.Mock;
test('fetches user data', async () => {
const user = await getUser('1');
expect(user).toEqual({ id: '1', name: 'John Doe' });
});
在這裡,使用 jest.fn
來模擬 fetch 函數,並返回預設的 JSON 資料,這樣就可以在不發出實際網路請求的情況下進行測試。
最後要介紹的,是 Jest 有內建支援測試覆蓋率報告,這可以幫助開發團隊了解測試程式碼覆蓋了多少應用程式的邏輯。只需在執行測試時多加上 --coverage
參數:
npx jest --coverage
運行後,就會得到一個詳細的報告,顯示每個文件的覆蓋率,包括函數、行數和分支的測試覆蓋情況。
這篇文章介紹了如何使用 TypeScript 與 Jest 撰寫單元測試,涵蓋了同步和異步測試、異常處理、模擬函數以及測試覆蓋率報告。透過 Jest 的強大功能與 TypeScript 的型別支援,更可以確保代碼質量並提高開發效率。