[리액트] Redux-Thunk 유닛 테스팅하기

심지훈·2021년 8월 7일
0

리액트

목록 보기
1/2

아래의 블로그를 참고하였습니다 !
https://decembersoft.com/posts/how-to-unit-test-redux-thunks/

배경

토이 프로젝트를 하면서 유닛테스팅을 같이 연습해보기로 했다.
리덕스 공식문서를 보면 Redux ToolKit(RTK)이란 라이브러리를 사용해서 테스팅을 설명하고 있다. RTK를 사용 할 준비가 안되었고, 배울려고 이리저리 보니 ..테스팅때문에 이미 멘탈이 나가 있어서 눈에 들어오지 않아 기존에 내가 하는 방식과 우선 비슷한 방식으로 테스팅 방법을 찾아보기로 했다.

환경

  • ES6+
  • React
  • Jest

방법

STEP 1

의존성을 찾아라.

const apiUrl = "http:/localhost:3001/word";
export const getWords = () => async (dispatch) => {
  dispatch(getWordsAction());
  try {
    const res = await axios.get(apiUrl);
    dispatch(getWordsSuccessAction(res.data));
  } catch (error) {
    dispatch(getWordsErrorAction(error));
  }
};

위는 간단한 형식의 썽크함수이다.
가장 먼저 테스트는 DB연결, API호출, 비동기 함수등과 같이 외부 모듈에 의존적이어서는 안된다. 그래서 가장먼저
의존성을 찾는것이다. 해당 썽크 함수에서는 비동기 API호출로 axios를 사용하고 있다. axios가 외부에 의존적인 모듈이라고 할 수 있겠다.

STEP 2

예상되는 결과를 정의하라.

axios는 REST API호출에 주로 쓰이고 promise를 반환하는 함수이다. axios의 결과에 따라 썽크함수의 내부 상태가 성공( Resolve), 실패(Rejected)로 나뉜다. 따라서 테스트 역시
호출(일반적으로 API호출 상태. Pending), 성공, 실패로 나누면 된다.

describe("getWords Thunk함수 테스트", () => {
  it("getWords Thunks함수를 호출합니다.", () => {});

  describe("getWords Thunk함수가 성공 했을떄 ", () => {});
  describe("getWords Thunk함수가 실패 했을때 했을떄 ", () => {});
});

STEP 3

테스팅 라이브러리를 통해 의존성 모듈을 Mocking 합니다.

저는 해당 블로그와 살짝 다르게 제가 생각하기에 가장 빠르고 쉽고 저에게 익숙한 일단 방식으로 했습니다. 구글링을 통해 axios을 mocking하는 방식을 찾았고 jest.mock을 통해 axios를 손쉽게 mocking 할 수 있었습니다.

jest.mock("axios");

을 통해 axios 모듈을 mocking 했습니다. 그리고 axios모듈이 반환하는 성공과 실패 값에 대한 값을 mocking합니다.

describe("getWords Thunk함수 테스트", () => {
  it("getWords Thunks함수를 호출합니다.", () => {});

  describe("getWords Thunk함수가 성공 했을떄 ", () => {
    const res = {
      data: [
        {
          word: "Korea",
          meaning: "Seoul",
        },
        {
          word: "Korea",
          meaning: "Seoul",
        },
        {
          word: "Korea",
          meaning: "Seoul",
        },
      ],
    };
    beforeEach(() => {
      axios.get.mockResolvedValue(res);
    });
  });
  describe("getWords Thunk함수가 실패 했을때 했을떄 ", () => {
    const error = new Error("My Error");
    beforeEach(() => {
      axios.get.mockRejectedValue(error);
    });
  });
});

axios함수를 mocking 해줬으므로 각 테스트를 돌리기전에 axios가 반환해야 할 값을 미리 정해줍니다.

  • 성공시
    axios는 데이터를 get해옵니다. 그 형태는 json값을 예상합니다. axios.get.mockResolvedValue을 통해 성공했을때 반환값을 mocking 합니다.
  • 실패시
    axios.get.mockRejectedValue를 통해 실패했을때 반환값을 mocking합니다.

STEP 4

테스트 작성

describe("getWords thunk test", () => {
  describe("dispatch getWords", () => {
    beforeEach(() => {
      const data = [
        {
          word: "Korea",
          meaning: "Seoul",
        },
        {
          word: "Korea",
          meaning: "Seoul",
        },
        {
          word: "Korea",
          meaning: "Seoul",
        },
      ];
      axios.get.mockResolvedValue(data);
    });
    it("dispatch getWords actions", async () => {
      const dispatch = jest.fn();
      await getWords()(dispatch);
      expect(dispatch).toHaveBeenCalledWith(getWordsAction());
    });
  });

  describe("dispatch getWords success", () => {
    const res = {
      data: [
        {
          word: "Korea",
          meaning: "Seoul",
        },
        {
          word: "Korea",
          meaning: "Seoul",
        },
        {
          word: "Korea",
          meaning: "Seoul",
        },
      ],
    };
    beforeEach(() => {
      axios.get.mockResolvedValue(res);
    });
    it("dispatch getWords actions", async () => {
      const dispatch = jest.fn();
      await getWords()(dispatch);
      expect(dispatch).toHaveBeenLastCalledWith(
        getWordsSuccessAction(res.data)
      );
    });
  });

  describe("dispatch getWords fail", () => {
    const error = new Error("My Error");
    beforeEach(() => {
      axios.get.mockRejectedValue(error);
    });
    it("dispatch getWords actions", async () => {
      const dispatch = jest.fn();
      await getWords()(dispatch);
      expect(dispatch).toHaveBeenLastCalledWith(getWordsErrorAction(error));
    });
  });
});

Thunk함수안에서 dispatch 될때 어떤 액션들이 제대로 호출되는지 확인 할 수 있습니다.
어떤 인자와 함께 dispatch 되는지 알아야하므로
dispatch = jest.fn()을 통해 dispatch 함수를 mocking함수로 바꿔줍니다.

jest.fn()의 원리는 https://www.daleseo.com/jest-fn-spy-on/ 해당 블로그를 많이 참조했습니다.

dispatch를 항상 감시하므로 성공,실패시에 정확한 액션들과 호출됬는지 테스팅합니다.

Thunk함수는 정상적으로 잘 작동 할것이라고 예상 할 수 있습니다.

profile
유연한 개발자

0개의 댓글