Jest使用筆記

簡介

  • 是一個由Facebook開發的JavaScript單元測試框架
  • 單元測試(Unit Test):針對程式中的最小單元進行測試
  • 主要對於function進行測試,是否符合預期運行結果

環境建置

使用npm安裝

npm install --save-dev jest
  • package.json檔案中增加指令
  • 可以在終端機輸入 npm run test 來執行jest測試
{  "scripts": {    "test": "jest"  }}// 查看測試覆蓋率{  "scripts": {    "test": "jest --coverage"  }}

設定配置文件

  • 輸入指令生成 jest.config 檔案
  • 在jest 29.7版中,已經可以直接使用ES6語法,不需另外安裝Babel
npm init jest@latest
  • 會問一些配置問題,根據需求選擇 jest設定問題

ps: 測試環境差別

  1. Node (testEnvironment: 'node')
  • 適合 Node.js 應用程序和伺服器端代碼提供的環境
  • 沒有 DOM 相關的全局變數(例如 window 或 document)
  • 最適合測試純 Node.js 代碼,例如服務器端邏輯
  1. JSDOM (testEnvironment: 'jsdom')
  • 是一個用 JavaScript 實現的 DOM 模擬器
  • 提供 DOM 相關的全局變數,像是 window 或 document
  • 可以在 Node.js 環境中模擬瀏覽器的行為,並測試那些與 DOM 互動的代碼
  • 最適合測試前端代碼,例如 React 或 Vue 組件

基本用法

1. 建立一個js檔案

  • 撰寫需要使用的function
  • 使用module.exports 把function輸出
// sum.jsfunction sum(a, b) {  return a + b;}module.exports = sum;

2. 建立一個test.js檔案

  • 使用require引入要測試的function
//sum.test.jsconst sum = require('./sum');test('測試 8+9 會等於17', () => {  expect(sum(8, 9)).toBe(17); // passed});

3. 基本語法

  • test / it:定義一個單元測試
test('該測試的說明', () => {    expect(要測試的function).toBe(預期的結果)})it('該測試的說明', () => {    expect(要測試的function).toBe(預期的結果)})
  • describe:定義群組單元測試,裡面可以放多個test
describe('測試加法函式', () => {  test('測試 8+9 會等於17', () => {    expect(sum(8, 9)).toBe(17);  });  test('測試 1+1 會等於2', () => {    expect(sum(1, 1)).toBe(2);  });});

🍞 Modifiers

  • not:用於表示否定
expect(1 + 2).not.toBe(4)
  • resolves:檢查一個 promise 是否成功
const promise = Promise.resolve('success');expect(promise).resolves.toBe('success');
  • rejects:檢查一個 promise 是否失敗
const promise = Promise.reject(new Error('failure'));expect(promise).rejects.toThrow('failure');

🍞 常用的Matchers

  • toBe:使用Object.is來比較是否相等,常用於原始型別
  • toEqual:進行深層次的值比較,適用於Object和Array的比較
test('object assign',() => {    const a = {}    expect(a).toBe({}) // failed    expect(a).toEqual({}) // passed})
  • toBeTruthy:檢查值是否為 truthy
  • toBeFalsy:檢查值是否為 falsy
describe('truthy or falsey' ,() => {    test('truthy', () => {      expect('Hello').toBeTruthy();    });    test('falsey', () => {        expect(0).toBeFalsy();    });})
  • toContain:檢查陣列是否包含某個特定元素
expect(['apple', 'banana', 'cherry']).toContain('banana');
  • toThrow: 檢查函數是否拋出錯誤
const throwFunction = () => {    throw new Error('error!');};expect(throwFunction).toThrow('error!');

Number的比較

  • toBeGreaterThan
  • toBeGreaterThanOrEqual
  • toBeLessThan
  • toBeLessThanOrEqual
describe('numbers', () => {  const value = 8 + 9;  test('8加9', () => {    expect(value).toBe(17);    expect(value).toBeGreaterThan(16);    expect(value).toBeLessThan(21);    expect(value).toBeLessThanOrEqual(18);  });});

🍞 非同步函式測試

  • 在node環境安裝axios
  • 取得一個todo測試
// async.jsconst axios = require('axios');const fetchData = async (id) => {  const res = await axios.get(`https://jsonplaceholder.typicode.com/todos/${id}`);  return res.data;};module.exports = fetchData;
  • 因為是非同步行為,要加上async…await
const fetchData = require('./async');test('it should return a todo', async () => {  const todo = await fetchData(1);  expect(todo.id).toBe(1);});

🍞 常在群組測試使用的方法

  1. beforeEach: 在每一個單元測試之前執行
  2. afterEach: 在每一個單元測試之後執行
  3. beforeAll: 在所有單元測試之前執行一次
  4. afterAll: 在所有單元測試之後執行一次
  • 寫在describe內,表示該組測試才會用到
// 使用 beforeEach 和 afterEachlet counter = 0;describe("Counter Tests", () => {        beforeAll(() => {            console.log('測試開始了')      });            afterAll(() => {            console.log('測試結束囉')        })    beforeEach(() => {        counter = 0;    });    afterEach(() => {        console.log(`Counter after test: ${counter}`);    });    test("Increment counter", () => {        counter++;        expect(counter).toBe(1);    });    test("Decrement counter", () => {        counter--;        expect(counter).toBe(-1);    });});

4. Mock用法

  • 可以不受外部依賴(資料庫 , API…),單純模擬測試功能
  1. jest.fn:創建模擬函式
const mockFn = jest.fn(scalar => 42 + scalar);mockFn(0); // 42mockFn(1); // 43
  1. mockReturnValue:設定回傳的值
const mockFn = jest.fn();mockFn.mockReturnValue(123);expect(mockFunction()).toBe(123);
  1. mockReturnValueOnce:只回傳一次,用於在連續調用中回傳不同的值
const mockFn = jest.fn();mockFn  .mockReturnValueOnce('first call')  .mockReturnValueOnce('second call');// 首次調用expect(mockFunction()).toBe('first call');// 第二次調用expect(mockFunction()).toBe('second call');
  1. jest.spyOn:用於偵測某物件的某方法是否被調用,也可以使用它來模擬方法的返回值或行為
  • 使用 jest.spyOn(axios, 'get') 來創建一個觀察 axiosget 方法的"間諜"
  • 這個"間諜"會攔截所有對 axios.get 的調用,並對它進行記錄
  • 使用 .mockReturnValueOnce() 方法來模擬 axios.get 在下一次調用時的返回值
// asynctest.test.jsconst fetchData = require('./async');const axios = require('axios')// 模擬axios.gettest('mock axios', async () => {  const spy = jest.spyOn(axios, 'get').mockReturnValueOnce({    data: {      id: 1,      todo: 'Do Homework!',    },  });  const res = await fetchData(1);  expect(res.todo).toBe('Do Homework!');    spy.mockRestore();});

參考資料

# JavaScript # Unit Test