20221124 TIL jest에서 모킹을 하는 다양한 방법
테스트에는 여러 계층이 있다.
각각의 테스트는 목적이 구분되어 있고, 따라서 그 목적에 맞게 테스트를 작성해주는 게 중요하다.
Unit test는 가장 빠르게 자주 돌려볼 수 있는 테스트로, 각각의 Unit이 정상적으로 작동하는지를 중점적으로 확인한다.
이 때 각각이 잘 돌아가는지 확인하는 것이기 때문에
다른 Unit에 의해 영향을 받아서 테스트가 깨지는 경우가 있다면
이는 해당 Unit만 제대로 테스트하고 있다고 보기 어렵다.
따라서 Unit테스트는 여러 외부 요인의 영향을 배제하기 위해
모킹을 이용해서 외부 요인들이 정상적으로 작동하는 것처럼 세팅을 해준다.
즉, Unit테스트는 나머지가 다 정상적일 때 해당 Unit도 의도대로 잘 동작하는지 확인하는 테스트이다.
통합 테스트는 영향을 줄 수 있는 Unit들을 함께 이용해서 테스트를 해보게 되고,
E2E테스트는 DB부터 UI까지 서비스가 정말 정상적으로 돌아가는지 테스트 해보게 된다.
jest는 자바스크립트 테스팅 프레임워크인데,
과제에서 jest로 리액트 컴포넌트들의 유닛 테스트를 작성하고 있다.
그런데 서버로부터 데이터를 받아오는 부분은 모킹을 하지 않으면
네트워크 환경 및 다양한 원인에 의해 유닛테스트가 실패할 수 있다.
따라서 모킹을 해야하는데, 모킹을 다양한 방법으로 할 수 있고, 상황에 맞게 방법을 선택해서 사용하면 좋을 것 같다.
1. 해당 테스트 내부에서 jest.mock('모킹할 모듈', () => (모듈이 정상적으로 반환할 때의 값));을 작성한다.
jest.mock('react-router-dom', () => ({
Link({ children, to }) {
return (
<a href={to}>
{children}
</a>
);
},
}));
위 코드처럼 react-router-dom의 Link를 사용하는 컴포넌트에서 테스트가 깨질 때 Link를 위 코드처럼 모킹할 수 있다.
2. 모킹할 모듈과 동일한 폴더 구조에 해당하는 위치에 __mocks__폴더를 만들고, 동일한 모듈 이름으로 모킹 파일을 작성한다.
테스트에서는 jest.mock('모킹할 모듈'); 만 작성해주면 된다.
동일한 모킹을 여러 테스트에서 하는 경우 이 방법을 사용하면 유용하다.
예를 들면 서버에서 데이터를 불러오는 ApiService를 여러 테스트에서 사용한다고 했을 때,
jest.mock('../services/ApiService', () => ({
apiService: {
async postSession({ accountNumber, password }) {
if (accountNumber === '1234' && password === 'password') {
return {
accessToken: 'ACCESS.TOKEN',
name: 'Tester',
amount: 100_000,
};
}
throw new Error('Login failed');
},
},
}));
이 코드를 아래 사진처럼 모킹하려는 모듈(ApiService)와 __mocks__가 동일 레벨에 있게 잡아주고,
그 내부에 동일한 파일 이름으로 모킹한 위 코드를 넣어준다.
그리고 해당 모킹을 해야되는 테스트에서 jest.mock('<path>/ApiService');만 써주면 모킹이 된다.
3. API모킹의 경우 MSW를 사용하기
프론트 모킹은 특히 API 모킹이 많은데, 테스트 서버를 띄워서 모킹할 수 있는 방법이다.
// src/testServer.js
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import config from './config';
const baseUrl = config.apiBaseUrl;
const server = setupServer(
rest.post(`${baseUrl}/session`, async (req, res, ctx) => {
const { accountNumber, password } = await req.json();
if (accountNumber === '12345678' && password === 'password') {
return res(
ctx.json({
name: 'Tester',
amount: 100_000,
accessToken: 'ACCESSTOKEN',
}),
);
}
return res(
ctx.status(400),
);
}),
);
export default server;
하고,
jest.config.js에서 setupFilesAfterEnv에
'./src/setupTestServer'
를 추가해준다.
한 가지 목적을 위한 다양한 방법을 알고 있으면 가장 좋은 방법을 선택하는 것이 쉬워지는 것 같다.
모든 방법을 처음부터 알 수는 없겠지만,
한 가지 방법을 쓰다가 더 나은 방법을 찾게 되면 따로 기록을 해둬서
상황에 맞게 가장 좋은 방법을 선택하는 방식으로 진행해보자.