使用 Jest 對 Redux 做單元測試 - Action 篇

使用 Jest 對 Redux 的 action 做單元測試的簡單記錄。

要怎麼測?

首先是要做前置作業,像是把一些東西 mock 起來。

Mock store

在處理非同步呼叫方面,由於是使用了一些 middleware 來幫我們處理,在這裡是用 redux-thunk,因此在做測試時,就必須把 store 給 mock 起來,在這裡就用 redux-mock-store 來做這件事情。

import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
const mockStore = configureMockStore([thunk]);

Mock Functions(Spy)

在函式(function)上包裹一層監聽器,讓我們能蒐集一些資訊來做檢測,例如:呼叫次數等。使用 jest.fn() 來做 mock。注意,對於引用進來的 module 要用 jest.mock mock 起來,例如:import module from 'module'; jest.mock(module);

Mock Request

可使用 fetch-mock 來偽造 request 與回傳結果,範例


記得要在 beforeEach 清除所有的 mock 紀錄。


初始設定

建立 store 的初始值 initialState,在每一次跑測試時會 reset (1) mock store (2) mock function 回到初始值。接著,在引用想要測試的 action 後,利用 store.dispatch 來觸發 「fetchListAction」 這個 action,

const initialState = { payload: [] };

beforeEach(() => {
  mockedStore = mockStore(initialState);
  mockedPromise = mockedStore.dispatch(fetchListAction());
});

要測什麼?

測試是否 dispatch 預期的 action 和回傳正確的結果、並依照正確的順序做呼叫。


在測試案例中,由於 redux-mock-store 會將所有 store 經 dispatch 觸發過的 action 記錄起來,因此可由 store.getActions(...) 來看到底(按順序)觸發了哪些事件和回傳的結果。接著,使用斷言庫(assertion library)來檢查是否符合預期。

先定義一個預期結果,稍等在檢查的時候會用到。

const EXPECTED_DATA = ['a', 'b', 'c'];

測試範例如下,先前定義的 mockedPromise 帶回了 fetchListAction 的回傳結果,接著檢測 (1) 觸發的 action (2) 回傳結果 是否符合預期。

describe('Fetch list', () => {
  test('save data to store', () => {
    const promise = mockedPromise.then(() => {
      // mock fetch request...(見備註)

      // mock store
      const actions = mockedStore.getActions();

      // 預期觸發 3 個 actions
      expect(actions.length).toBe(3);

      // 檢視觸發的第二個 actions,其 type 是否符合預期想觸發的 action
      expect(actions[1].type).toEqual(SET_LIST_DATA);

      // 檢視觸發的第二個 action,其回傳結果是否符合預期,希望要等於 EXPECTED_DATA
      expect(actions[1].payload).toEqual(EXPECTED_DATA);
    });
  });
});

[備註] 由於目前專案上是比較特別的用法,而不是用官網範例方式 mock request,因此這邊就省略這部份的程式碼。

其他

關於檢查是否正確觸發預期的 action 可以這樣寫

expect(actions[1].type).toEqual(SET_LIST_DATA);
expect(actions[1].payload).toEqual(EXPECTED_DATA);

等同於

const expectedAction = {
    type: SET_LIST_DATA,
    payload: EXPECTED_DATA,
};

expect(actions[1]).toEqual(expectedAction);

檢查 dispatch 的 action 數,雖然也是一種檢查方法,但相較上面仔細檢查 action type 來說較為偷懶。

// 預期觸發 3 個 actions
expect(actions.length).toBe(3);

參考資料

推薦閱讀


使用 Jest 對 Redux 做單元測試 - Reducer 篇


Jest redux redux-mock-store redux-thunk Unit Test 自動化測試 單元測試