Jest는 javaScript 테스트 프레임워크다. 가볍고 쉬우며 뛰어난 mock function을 지원해서 많이 사용하는 것 같다.
더군다나 facebook이 만들었으니 react, node.js를 사용하는 개발자들에겐 거의 빠지지않을 툴일 것이다.
오늘 test case를 작성하고 검사하는데 axios에서 mocking이 적용이 잘 안되서 적어두면 나중에라도 도움이 될 것 같아서 적어본다.
보통은 공식문서에서 참고해 개발하면 쉽게 따라할 수 있지만 생각보다 잘 안되는게 axios를 mocking할 때, 흔히 하는 실수들이다.
크게 보면 두가지 경우라고 볼 수 있다.
라이브러리는 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을 만들어내려고 한다.
그러면 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