리액트 프로젝트에서 코드 품질을 확보하고 버그를 줄이려면 테스트는 필수죠!
특히 요즘처럼 복잡한 기능들이 잔뜩 들어간 웹 서비스를 만들 때는, 코드 수정이나 기능 추가 후 예상치 못한 문제가 생기는 걸 방지하기 위해 테스트를 꼼꼼히 해줘야 해요.
그런데, 테스트 코드를 작성하는 게 막막하게 느껴지기도 하고, 어디서부터 시작해야 할지 몰라 망설여지는 분들도 있을 거예요.
오늘은 Vitest라는 멋진 테스트 프레임워크를 활용해서, 리액트 컴포넌트를 효과적으로 테스트하는 방법을 알려드릴게요! Vitest는 Vite 기반의 테스트 프레임워크라서 Vite 프로젝트와 찰떡궁합이고, Jest와 비슷한 API를 제공해서 Jest를 써봤던 분들이라면 금방 적응할 수 있답니다.
Vitest 설치 및 설정: 든든한 기반 마련하기
Vitest를 사용하려면 먼저 프로젝트에 설치해야겠죠? 필요한 패키지들을 설치해 줍시다. React Testing Library도 함께 설치하면 컴포넌트 테스트를 더욱 쉽게 할 수 있어요.
yarn add -D vitest @testing-library/react @testing-library/jest-dom msw
끝났으면 Vitest 설정 파일을 만들어야 해요.
보통 라는 이름으로 프로젝트 루트에 파일을 생성하는데, 이 파일에서 Vitest의 동작 방식을 설정할 수 있답니다.
/// <reference types="vitest" />
/// <reference types="vite/client" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['./src/setup-tests.ts'],
},
});
vitest.config.ts
이 설정 파일에서 몇 가지 중요한 옵션들을 설정해 줬어요.
- globals: true: Vitest의 API를 전역적으로 사용할 수 있도록 설정했어요. 그래야 describe, it, expect 같은 함수를 import하지 않고 바로 사용할 수 있답니다.
- environment: 'jsdom': jsdom 환경을 사용해서 브라우저 환경을 시뮬레이션하는 거예요. 테스트를 실행할 때 실제 브라우저를 띄우지 않고 jsdom에서 테스트를 실행하면 속도가 훨씬 빨라지죠.
- setupFiles: ['./src/setup-tests.ts']: 테스트 실행 전에 파일을 실행하도록 설정했어요. 테스트 환경을 초기화하거나 필요한 설정을 하는 작업을 이 파일에 담으면 깔끔하게 관리할 수 있답니다.
테스트 환경 초기화: 준비운동은 필수!
자, 이제 Vitest 설정 파일을 만들었으니, 파일을 만들어서 테스트 환경을 초기화해 볼게요.
import * as matchers from '@testing-library/jest-dom/matchers';
import { expect } from 'vitest';
import { cleanup } from '@testing-library/react';
expect.extend(matchers);
afterEach(() => {
cleanup(); // 각 테스트 종료 후 DOM 요소 제거
});
setup-tests.ts
이 파일에서는 주로 테스트를 실행하기 전에 필요한 환경을 설정하는 작업을 해요. 예를 들어, React Testing Library의 를 에 확장해서 같은 유용한 매처들을 사용할 수 있게 만들어 줬어요.
또, 각 테스트가 끝난 후에 함수를 실행해서 DOM을 깨끗하게 정리해 주는 것도 잊지 말아야 해요. 그래야 다음 테스트가 이전 테스트의 영향을 받지 않고 깨끗한 상태에서 시작할 수 있답니다.
API Mocking 설정: 실제 API는 잠시 쉬어가세요!
테스트를 할 때, 실제 API를 호출하면 테스트 결과가 외부 환경에 의존적이 되고, 테스트 속도가 느려질 수 있어요.
그래서 (Mock Service Worker)를 사용해서 API를 가짜로 만들어 테스트 환경을 독립적으로 유지하는 게 좋답니다.
MSW로 API Mock 서버 구축
먼저 파일을 만들어서 Mock Server를 설정해 줍시다.
import { setupServer } from 'msw/node';
import { rest } from 'msw';
const server = setupServer(
rest.get('/api/data', (req, res, ctx) => {
return res(ctx.json({ data: 'mocked data' }));
})
);
export { server };
Mock 서버, 테스트 초기화 파일에 연결하기
이제 파일에 Mock Server를 연결해 줘야 테스트 환경에서 Mock Server가 작동하게 됩니다.
import { server } from './mocks/server'; // 위에서 생성한 server.js
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
하면 각 테스트 실행 전에 Mock Server가 시작되고, 각 테스트가 끝난 후에는 Mock Server의 핸들러를 초기화하고, 모든 테스트가 끝난 후에는 Mock Server가 종료됩니다.
테스트 코드 작성: 실력 발휘할 시간!
드디어 테스트 코드를 작성할 차례에요! 이제 컴포넌트가 제대로 동작하는지 확인하는 테스트 코드를 작성해 볼게요.
테스트 대상 컴포넌트
먼저 테스트할 컴포넌트를 만들어 봅시다. 아래 예시는 API를 호출해서 데이터를 가져오고, 데이터가 로딩 중일 때는 "Loading..."을, 데이터를 가져온 후에는 데이터를 화면에 표시하는 간단한 컴포넌트에요.
import React from 'react';
const MyComponent = () => {
const [data, setData] = React.useState(null);
React.useEffect(() => {
fetch('/api/data')
.then(response => response.json())
.then(data => setData(data));
}, []);
return <div>{data ? data.data : 'Loading...'}</div>;
};
export default MyComponent;
컴포넌트 테스트 코드 작성
이 컴포넌트에 대한 테스트 코드를 파일에 작성해 봅시다.
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
test('renders loading state initially', () => {
render(<MyComponent />);
expect(screen.getByText(/loading/i)).toBeInTheDocument();
});
test('renders mocked data after fetch', async () => {
render(<MyComponent />);
expect(await screen.findByText(/mocked data/i)).toBeInTheDocument();
});
테스트 코드 해설
첫 번째 테스트 는 컴포넌트가 처음 렌더링될 때 "Loading..."이라는 텍스트가 화면에 나타나는지 확인하는 테스트에요.
두 번째 테스트 는 API 호출 후 Mock Server에서 정의한 "mocked data"가 화면에 표시되는지 확인하는 테스트랍니다.
테스트 실행: 결과 확인하기
이제 작성한 테스트 코드를 실행해 볼까요? 다음 명령어를 사용해서 테스트를 실행할 수 있어요.
yarn test
혹시 코드를 수정할 때마다 자동으로 테스트를 실행하고 싶다면, 다음 명령어를 사용하면 됩니다.
yarn test:watch
테스트 결과 확인
테스트가 실행되면 콘솔에 테스트 결과가 표시됩니다. 테스트가 성공하면 녹색으로, 실패하면 빨간색으로 표시될 거예요. 테스트가 실패하면 어떤 부분에서 문제가 발생했는지 자세한 정보가 함께 표시되니, 오류 메시지를 참고해서 코드를 수정하면 된답니다.
Vitest와 React Testing Library로 테스트 환경 구축하기 위한 핵심 정리
Vitest | Vite 기반의 빠르고 유연한 테스트 프레임워크 |
React Testing Library | 리액트 컴포넌트를 사용자 관점에서 테스트할 수 있도록 도와주는 라이브러리 |
jsdom | Node.js 환경에서 브라우저를 시뮬레이션하여 테스트 환경을 제공 |
MSW | Mock Service Worker, 테스트 환경에서 실제 API 호출을 피하고 가짜 응답을 반환 |
vitest.config.ts | Vitest 설정 파일, 테스트 환경을 설정 |
setup-tests.ts | 테스트 환경 초기화 파일, 테스트 실행 전에 필요한 설정 수행 |
기능 설명
QnA
Q1. Vitest와 Jest는 어떤 차이가 있나요?
A1. Vitest는 Vite 기반의 테스트 프레임워크이고, Jest는 Node.js 기반의 테스트 프레임워크에요. Vitest는 Jest와 유사한 API를 제공하지만 Vite와의 통합이 더욱 뛰어나고, 빠른 속도를 자랑한답니다.
Q2. React Testing Library는 왜 사용하는 건가요?
A2. React Testing Library는 리액트 컴포넌트를 사용자 관점에서 테스트할 수 있도록 도와주는 라이브러리에요. 실제 사용자가 컴포넌트를 사용하는 방식과 유사하게 테스트를 작성할 수 있어서, 컴포넌트가 의도한 대로 동작하는지 쉽게 확인할 수 있답니다.
Q3. MSW를 사용하는 이유는 뭘까요?
A3. MSW는 테스트 환경에서 실제 API를 호출하지 않고 가짜 응답을 반환해주는 Mock Service Worker에요. 실제 API를 호출하면 테스트 속도가 느려지고, 테스트 결과가 외부 환경에 의존적이 될 수 있기 때문에, 테스트를 안정적으로 수행하기 위해 MSW를 사용한답니다.
마무리
Vitest와 React Testing Library를 활용하면 리액트 컴포넌트를 효과적으로 테스트할 수 있어요. 특히 MSW를 통해 API Mocking을 설정하면 외부 의존성을 제거하고 안정적인 테스트 환경을 구축할 수 있고, 덕분에 코드 품질을 향상시키고 버그를 미리 잡아낼 수 있죠.
이 글이 여러분의 리액트 프로젝트에 테스트 코드를 도입하는 데 도움이 되었으면 좋겠어요!
키워드:리액트,React,Vitest,테스트,테스트코드,테스팅,프레임워크,ReactTestingLibrary,JS,JavaScript,개발,개발자,코드품질,버그,MSW,MockServiceWorker,API,Mocking,JSdom,Vite,프론트엔드,Frontend,웹개발,WebDevelopment,자동화,CI,CD,설정,초보자,중급자,고급,팁,강좌,튜토리얼,정보,공유,소통,함께해요