先說最終目的:避免每個 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
意思就是:
如果你在測試後太懶惰以至於不清理你的數據庫、文件系統或基於內存的對象,那麼考慮轉行。這個工作不適合你
雖然這句話還蠻重的,不過也大大凸顯出清除測試資料的重要性,當我們單元測試的測試資料互相干擾時,我們最後測出的結果就不會是準確的,就無法具有 可信任的 的特性,那我們做的測試其實就沒有意義了
當我們在 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.mockClear()
最常用