[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() | ❌ | |
還原 function | jest.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() | ✅ | |
還原 function | jest.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() | ✅ | |
還原 function | jest.fn() | ✅ |
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()
最常用