iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0

在現在的前端應用程式開發中,撰寫測試對於確保代碼的穩定性和可維護性非常重要。而 Jest 就是盛行的其中一個 JavaScript 測試框架,內建支援斷言庫和模擬功能,適合撰寫單元測試、端對端測試等。因為 TypeScript 結合 Jest,可以為我們的測試代碼提供型別檢查,進一步避免潛在的錯誤。

在今天的文章中,我將介紹如何使用 TypeScript 與 Jest 撰寫測試,並提供一些簡單範例來展示實際應用。

一、安裝 Jest 與 TypeScript

在開始撰寫測試之前,需要安裝相關的依賴項。

1. 先安裝 Jest 及其 TypeScript 支援套件

npm install --save-dev jest ts-jest @types/jest
  • jest:Jest 本身。
  • ts-jest:將 Jest 與 TypeScript 結合的套件。
  • @types/jest:Jest 的 TypeScript 型別定義,讓開發者在寫測試時有型別提示。

2. 安裝完成後,配置 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 函數,它的功能是將兩個數字相加:

1. 程式碼

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 來斷言結果是否符合預期。

  • test:用來定義一個測試案例,描述一段特定的測試邏輯。
  • expect:斷言函數,檢查結果是否與預期相符。
  • toBe:檢查結果是否嚴格相等。

2. 運行測試

(1) 方法一:

npx jest

(2) 方法二:

添加下列這段到 package.json 的 scripts 區塊中,這樣就可以簡單使用 npm test 指令來執行測試。

{
  "scripts": {
    "test": "jest"
  }
}

運行結果應該顯示所有測試通過,並且 Jest 會顯示測試的執行時間和每個測試案例的結果。

三、處理異步測試

很多時候,我們會有處理一些異步操作的情形,例如 API 請求或資料庫查詢。在撰寫異步函數測試時,可以利用 Jest 的異步支援。

1. 情境範例:

假設我們有一個 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 即可

2. 斷言異常情況

如果函數拋出異常,可以使用 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 來檢查是否會拋出指定的錯誤訊息。

四、模擬(Mocking)

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 的型別支援,更可以確保代碼質量並提高開發效率。


上一篇
Day28:TypeScript 的實用工具與插件
下一篇
Day30:TypeScript 在大型應用中的應用淺談
系列文
用 TypeScript 重新定義前端開發:30 天的實踐與思考30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言