티스토리 뷰

728x90

velog 블로그에서 tistory로 이전한 데이터 입니다. 2020-10-26

들어가기

Jest는 javaScript 테스트 프레임워크다. 가볍고 쉬우며 뛰어난 mock function을 지원해서 많이 사용하는 것 같다.
더군다나 facebook이 만들었으니 react, node.js를 사용하는 개발자들에겐 거의 빠지지않을 툴일 것이다.

오늘 test case를 작성하고 검사하는데 axios에서 mocking이 적용이 잘 안되서 적어두면 나중에라도 도움이 될 것 같아서 적어본다.

사용기

보통은 공식문서에서 참고해 개발하면 쉽게 따라할 수 있지만 생각보다 잘 안되는게 axios를 mocking할 때, 흔히 하는 실수들이다.

크게 보면 두가지 경우라고 볼 수 있다.

  1. axios를 import해서 사용할 때,
  2. axios.create를 이용해서 인스턴스를 사용할 때,

라이브러리는 axios-mock-adapter를 추가로 많이 사용할 것이다. 하지만 생각보다 재대로 적용되지 않은 경우가 있었다.

상황

나의 목적은 500, 200, 404에러를 고의로 발생시켜 그에 따른 Error를 핸들링할 수 있는 기능 을 만드는 일이였고
상황은 1번에 처음에 axios-mock-adapter를 사용했다.

axios-mock-adapter를 사용하면 쉽게 axiosMock.onGet( {:주소} ).reply(200) 등으로 쉽게 테스트가 가능한데 계속 404 에러가 나왔다.

당연히 주소 부분에 서버가 켜져있지 않았기 때문에 404에러가 당연한 결과지만 테스트에서 200, 500을 만들고 싶었기 때문에 mocking이 안됐음을 알 수 있다.

고민하기

우리는 자체 axios default instance를 사용하고 있었기 때문에 왜 mock adapter가 필요한지 고민을 했다. jest 도큐먼트를 읽어보면 axios에 대해 mock 함수를 다루는 방법이 나와있었다.

// users.test.js
import axios from 'axios';
import Users from './users';

jest.mock('axios');

test('should fetch users', () => {
  const users = [{name: 'Bob'}];
  const resp = {data: users};
  axios.get.mockResolvedValue(resp);

  // or you could use the following depending on your use case:
  // axios.get.mockImplementation(() => Promise.resolve(resp))

  return Users.all().then(data => expect(data).toEqual(users));
});
// https://jestjs.io/docs/en/mock-functions 에서 확인이 가능하다.

이때, jest.mock은 내부 코드를 보면 일부지만 Instance에 대한 새로운 mock을 만들어내려고 한다.
mock code

그러면 jest.mock('axios')는 axios를 copy해 새로운 instance로 변경해 테스트가 가능하다는 점이다.

반면에 axios-mock-adapter는?

2번 상황에 맞는 코드를 작성할 때, adapter의 사용이 맞는 것 같다. 여기

내부 코드를 자세히 살펴보진 못했지만 사람들이 404에러가 발생한 경우에 대해서 많이들 글을 남긴게 있다.
뭐 누구는 browser에서 사용하는데 react 컴포넌트 검사에서 storybook과 raceCondition 문제가 있어서 할 수 없다는 의견도 많고 다른 의견들도 많지만 생략한다.

axios.create를 통해 새로운 인스턴스를 얻어서 mock-adapter에 넣고 쓰면 알맞을 것 같다.
default에서는 axios-mock-adapter를 사용하지 않을 예정이다.

해결 코드 예시

// sudo code
jest.mock('axios');

test('RESPONSE 200 테스트',async ()=>{
    // 1. 에러나고 난 뒤 실행될 함수를 mock function 만듬
        func = jest.fn().mockResolvedValue([]);

        // 2. axios.post 에 대해 200 
    axios.post.mockImplementation(()=>
            Promise.resolve( { response: { status: 200 } } )
        );

        // 1번 경우의 함수가 불리지 않았는지 체크 
        expect(func).not.toHaveBeenCalled();
 });

test('RESPONSE 500 테스트',async ()=>{
    // 1. 에러나고 난 뒤 실행될 함수를 mock function 만듬
        func = jest.fn().mockResolvedValue([]);

        // 2. axios.post 에 대해 500 에러를 발생
    axios.post.mockImplementation(()=>
            Promise.reject( { response: { status: 500 } } )
        );

      // 1번 경우에 해당하는 함수가 불렸는지 체크
         expect(func).toHaveBeenCalled();
});

참고

axios-mock-adapter
https://github.com/ctimmerm/axios-mock-adapter/issues/193
https://jestjs.io/docs/en/mock-functions#mocking-modules

반응형