project:
framework:
- nestjs
- jest
versions:
nodejs: 14.2
typescript: 3.7
nest: 7.0
jest: 25.1
당연한 이야기지만 어떤 기능을 개발할 때, 테스트는 필수적입니다. 단위 테스트, 통합 테스트 등 테스트의 종류도 많고, 각 테스트를 올바르게 실행하기 위해서는 다양한 테스트 케이스도 필요합니다. 그리고 이 다양한 테스트 케이스를 위해서는 "데이터"가 필요합니다.
데이터는 직접 개발 환경 DB 에 만들어 넣을 수도 있고, 임의의 Mock 데이터를 만들수도 있습니다. 실제 환경과 비슷한 테스트를 위해서는 당연히 실제 DB 에 데이터를 만들어서 넣는게 좋겠지만, 테스트 도중에 데이터의 타입이나 구성이 변경되면 모든 테스트 데이터를 다시 만들어 넣거나, 모두 수정해야하는 번거로운 작업이 생길 수도 있습니다. 경우에 따라서는 좀더 간단한 Mock 데이터를 이용해 테스트하고 데이터의 변경이나 수정에 빠르게 대응하다가 최종적인 테스트에는 직접 DB 에 데이터를 만들어 넣어서 테스트를 하는 것이 더 편할 수도 있습니다.
이번 포스트에서는 JSON 파일을 이용해 Mock 데이터를 만들고, 그 Mock 데이터를 이용해 테스트를 진행하는 방법을 정리해보려고 합니다.
데이터가 필요한데 아직 데이터를 넣는 기능도 없고 데이터의 타입도 정해지지 않았다.
예를 들어, 매일 유저의 걸음수를 기록하여 1개월, 3개월, 6개월 단위로 걸음수의 기록을 그래프로 볼 수 있는 기능이 필요하다고 가정하겠습니다.
단순히 DB 의 기간별 데이터를 쿼리를 통해 가져와서 전달해주면 됩니다. 기능도 다 만들었고 테스트를 하려고 하는데 데이터가 문제입니다. 아직 걸음수를 DB 에 저장하는 기능이 개발되지 않은 상황이라 직접 데이터를 만들어서 넣어야 테스트를 할 수 있는데 저장할 데이터의 타입이 계속 변경되고 있는 상황입니다. 직접 만들어서 DB 에 넣는게 제일 좋지만 컬럼이 추가되거나 컬럼의 데이터 타입이 변경되면 그걸 다시 다 수정해야합니다.
좀더 간편한 방법은 없을까요?
데이터만의 문제라면 json 파일로 Mock 데이터를 만들어서 불러오자
앞에서 말했듯, 이런 경우에는 DB 에 직접 데이터를 만들어 넣기보다 임의의 Mock 데이터를 만들어서 기능 자체만 테스트하는 것이 좀더 간결할 수 있습니다. 대량의 데이터가 필요한 경우에도 물론 Mock 데이터를 이용하는 편이 간편합니다.
Mock 데이터를 json 파일로 만들고 그 json 파일로부터 데이터를 가져오는 코드를 작성해보겠습니다.
아래의 예제 코드는 오늘 날짜로부터 N 일 전까지의 걸음수 데이터를 만들어 mock-step-history.json 파일로 만드는 코드입니다. count 파라미터를 통해 생성하고자 하는 데이터의 갯수를 지정합니다.
const putMock = async (count: number) => {
const today = new Date();
const max = 30000; // max step
const min = 100; // min step
// mock data 생성
const data = [...Array(count).keys()].map(num => {
// step: random, 100 ~ 30,000 사이의 걸음수
const step = Math.floor(Math.random() * (max - min)) + min;
// num 일 전의 날짜 생성
const current = new Date();
const date = new Date(current.setDate(today.getDate() - num))
.toLocaleDateString()
.split('/');
const recordedAt = `${date[2]}-${date[0]}-${date[1]}`; // ex) 2023-7-4
// data
return {
id: `${num + 1}`, // 중복되지 않는 값
step,
recordedAt,
createdAt: current.toISOString(),
updatedAt: current.toISOString(),
};
});
// json 파일 생성
fs.writeFileSync(
`${__dirname}/mock/mock-step-history.json`,
JSON.stringify(data),
);
};
아래의 jest 코드를 이용해 실행할 수 있습니다.
it.only('put mock', async () => {
jest.setTimeout(200_000_000);
await putMock(200);
expect(true);
});
아래의 코드는 3-1) 에서 생성한 mock-step-history.json 을 불러오는 코드입니다.
const fetchMock = async (): Promise<object[]> => {
const file: string = fs.readFileSync(
`${__dirname}/mock/mock-step-history.json`,
'utf8',
);
return JSON.parse(file).data;
};
jest.spyOn().mockImplementation() 을 이용해 데이터를 가져오는 메소드(DB쿼리를 실행하는 메소드나 I/O 관련 메소드)를 fetchMock()
로 Mocking 하고, 테스트를 해봅니다.
it.only('fetchUserStep', async () => {
jest.setTimeout(200_000_000);
// fetchUserStepHistory 라는 메소드가 fetchMock 함수의 결과값을 return 하도록 Mocking 한다.
jest.spyOn(service, 'fetchStepHistory').mockImplementation(
async (id: string): Promise<any[]> => {
return fetchMock();
},
);
const result: any = await service.fetchUserStep(param);
console.debug(TAG, 'result', JSON.stringify(result));
expect(result).toBeDefined();
});
1) putMock()
함수를 통해 원하는 타입의 mock 데이터를 json 파일로 생성
2) 서비스의 데이터를 가져오는 메소드를 fetchMock()
함수로 Mocking
3) 테스트 진행
이 과정은 제가 최근에 겪은 경험을 기반으로 정리한 것입니다. 1개월, 3개월, 6개월, 1년, 2년 치의 데이터를 가져와서 프론트로 넘겨주는 API 를 개발해야 했는데 데이터가 아예 없어서 곤란했던 적이 있었습니다. 그리고 DB 에 저장하는 데이터 타입도 확정되지 않은 상황이라 무턱대고 데이터를 만들어서 개발 DB 에 넣었다가, 나중에 다시 수정하는게 상당히 귀찮을 것 같았습니다.
이렇게 한 덕분에 데이터 타입이 확정될 때까지 변경 사항 있어도 손쉽게 수정하고 테스트를 진행할 수 있었습니다.