Skip to main content

[Unit Test] 3.2 - 每個測試都該是獨立的,那些你該清的 api mock data

為什麼要清除 mocking api function?​

先說最終目的:避免每個 test case 的結果互相干擾

在單元測試的藝術中 (Section 8.2.4) 中有提到:

Laziness in cleanup—If you’re too lazy to clean up your database after testing, your filesystem after testing, or your memory-based objects, consider moving to a different profession. This isn’t a job for you


意思就是:

如果你在測試後太懶惰以至於不清理你的數據庫、文件系統或基於內存的對象,那麼考慮轉行。這個工作不適合你


雖然這句話還蠻重 😱 的,不過也大大凸顯出清除測試資料的重要性,當我們單元測試的測試資料互相干擾時,我們最後測出的結果就不會是準確的,就無法具有 可信任的 的特性,那我們做的測試其實就沒有意義了


不同的 clean up utils​

當我們在 mocking api 時,是將 api function 覆寫成 jest.fn,接著在 jest.fn 客製化我們的 api response

jest.fn 會去記錄一些我們 call api 的過程,像是:

  • 呼叫了幾次
  • 呼叫時帶了什麼參數

這時候,我們就可以利用以下三個 utils 來幫我們清除每個 test cases 不同類型的資料:

  • mock.mockClear()
  • mock.mockReset()
  • mock.mockRestore()

這三個 util 各有不同的主要功能,就讓我們來看一下吧~


mock.mockClear()​

會覆寫掉 mock api 相關的紀錄,像是 呼叫的次數、產生的實例數量 等,但不會清除需要引入的 input 或輸出的 output 等條件

主要目的mock 值是否被移除
呼叫後相關紀錄mockFn.mock.calls✅
mockFn.mock.instances✅
mockFn.mock.contexts✅
模擬 function 行為mockFn.mockImplementation()❌
mockFn.mockReturnValue()❌
mockFn.mockResolvedValue()❌
還原 functionjest.fn()❌


mock.mockReset()​

會覆寫掉 mock api 相關的紀錄,像是 呼叫的次數、產生的實例數量 等,也會清除需要引入的 input 或輸出的 output 等條件,把 jest.fn 變成 undefined

主要目的mock 值是否被移除
呼叫後相關紀錄mockFn.mock.calls✅
mockFn.mock.instances✅
mockFn.mock.contexts✅
模擬 function 行為mockFn.mockImplementation()✅
mockFn.mockReturnValue()✅
mockFn.mockResolvedValue()✅
還原 functionjest.fn()❌


mock.mockRestore()​

會覆寫掉 mock api 相關的紀錄,像是 呼叫的次數、產生的實例數量 等,也會清除需要引入的 input 或輸出的 output 等條件,甚至還原成原本的 function,不再是 jest.fn

主要目的mock 值是否被移除
呼叫後相關紀錄mockFn.mock.calls✅
mockFn.mock.instances✅
mockFn.mock.contexts✅
模擬 function 行為mockFn.mockImplementation()✅
mockFn.mockReturnValue()✅
mockFn.mockResolvedValue()✅
還原 functionjest.fn()✅


:::info注意:此函式在使用 jest.spyOn 下才可以使用,一般的 jest.fn() 無法使用此函式 :::


實際使用​

在我現在的開發經驗中,我們的情境只需要去清除 呼叫的相關紀錄,所以我們選用了 mock.mockClear 來作為 clear api 的紀錄,不用另外去清除 api response

以下為實際範例:

describe('ThirdPartySources', () => {
beforeEach(() => {
mockApiGetUsers.mockResolvedValue(defaultMockApiGetUsers);
});

afterEach(() => {
mockApiGetUsers.mockClear();
});

test('when there is no azure, okta is in ad sources, should show refresh status button', async () => {
// Act
const { findByTestId } = renderWithRedux(<ThirdPartySources></ThirdPartySources>);
const refreshBtn = await findByTestId(idBtnConnectionStatus);

// Assert
expect(refreshBtn).toBeVisible();
});
});

結論​

  • 知道清除 mock data 的重要性,是為了要保持每個單元測試獨立運作
  • 知道 jest 提供 3 個 util 幫助我們清理 mock data,以實務上來說 mock.mockClear() 最常用

參考資訊​