
Vitest는 Vite 기반의 테스트 프레임워크로, 빠른 속도와 효율적인 설정으로 주목받고 있다.
특히 Vite를 사용해 구성된 프로젝트에서 별도의 설정 없이 Vitest를 바로 사용할 수 있다는 점이 큰 장점이다.
예시 코드>
import { renderHook } from '@testing-library/react-hooks';
import useSearch from 'hooks/useSearch';
describe('useSearch Hook', () => {
it('초기 검색어가 비어있어야 한다', () => {
const { result } = renderHook(() => useSearch());
expect(result.current.searchTerm).toBe('');
});
it('검색어가 업데이트 되어야 한다', () => {
const { result } = renderHook(() => useSearch());
result.current.setSearchTerm('Test');
expect(result.current.searchTerm).toBe('Test');
});
});
이 예시에서, TDD 방식을 사용하여 useSearch 훅이 정상적으로 검색어를 업데이트하는지 검증한다. Vitest는 테스트 실행이 빠르기 때문에 개발자는 코드 작성 후 테스트를 즉각적으로 확인하고, 테스트가 실패할 경우 필요한 수정 작업을 빠르게 반복할 수 있다.
MSW는 네트워크 요청을 가로채고 이를 모킹하여 실제 API 서버가 없어도 테스트를 진행할 수 있도록 도와주는 도구.
특히 외부 API에 의존하는 코드에서 Vitest와 함께 MSW를 사용하면, 테스트가 더 일관되게 실행될 수 있다.
msw 핸들러
import { findEventIndexById } from '@utils/findUtil';
import { http, HttpResponse } from 'msw';
import { Event, EventForm } from '../types';
import { events } from './response/events.json' assert { type: 'json' };
export function notFound() {
return new HttpResponse(null, { status: 404 });
}
let mockEvents = [...events];
beforeEach(() => {
mockEvents = [...events]; // 원본 데이터로 초기화
});
export const handlers = [
// GET: 모든 이벤트 조회
http.get('/api/events', async () => {
return HttpResponse.json({ events: mockEvents });
}),
// POST: 새로운 이벤트 추가
http.post('/api/events', async ({ request }) => {
// 이벤트 추가 로직
return HttpResponse.json(updatedEvent, { status: 201 });
}),
// PUT: 특정 ID 이벤트 업데이트
http.put('/api/events/:id', async ({ params, request }) => {
// 이벤트 업데이트 로직
return HttpResponse.json(mockEvents[index]);
}),
// DELETE: 특정 ID의 이벤트 삭제
http.delete('/api/events/:id', ({ params }) => {
// 이벤트 삭제 로직
return new HttpResponse(null, { status: 204 });
}),
];
setupTest.ts
import { setupServer } from 'msw/node';
import '@testing-library/jest-dom';
import { handlers } from './__mocks__/handlers';
import { setupMockHandlers } from './__mocks__/handlersUtils';
import { events } from './__mocks__/response/events.json' assert { type: 'json' };
import { Event } from './types';
/* msw */
export const server = setupServer(...handlers);
const initialEvents = [...events] as const;
vi.stubEnv('TZ', 'UTC');
beforeAll(() => {
server.listen();
vi.useFakeTimers({ shouldAdvanceTime: true });
});
beforeEach(() => {
server.use(...setupMockHandlers([...initialEvents] as Event[]));
expect.hasAssertions();
vi.setSystemTime(new Date('2024-11-01'));
});
afterEach(() => {
server.resetHandlers();
vi.clearAllMocks();
});
afterAll(() => {
vi.resetAllMocks();
vi.useRealTimers();
server.close();
});
날짜에 대한 검색이 있기 때문에 각 테스트가 시작할 때 2024-11-01로 날짜를 지정해준다.
테스트가 독립적으로 실행될 수 있도록 핸들러를 초기화 해준다.
Factory.ts는 테스트에서 반복적으로 사용되는 데이터 생성을 자동화하는 유틸리티.
TDD를 진행하면서 다양한 상황에 맞는 데이터가 필요할 때, Factory.ts를 통해 쉽게 데이터를 생성할 수 있다.
// Factory.ts
interface Event {
id: string;
title: string;
date: Date;
}
export const createEvent = (overrides = {}) => ({
id: Math.floor(Math.random() * 1000),
title: 'Default Event Title',
date: '2024-11-09',
...overrides,
});
활용 예시
import { renderHook } from '@testing-library/react-hooks';
import { createEvent } from '__mocks__/Factory';
describe('useTest Hook', () => {
it('사용자가 원하는 형식의 이벤트 객체 생성', () => {
const customEvent = createEvent({ title: 'Custom Event', id: 999 });
expect(customEvent.title).toBe('Custom Event');
expect(customEvent.id).toBe(999);
});
});