도입 – 학습 목표 및 필요성
🔗 관련 에러 해결 가이드
React Testing Library로 테스트 작성하기는 현대 프론트엔드 개발에서 필수적인 스킬입니다. 많은 개발자들이 코드를 작성하는 데는 익숙하지만, 테스트 작성은 어렵게 느낍니다. React Testing Library는 사용자 관점에서 컴포넌트를 테스트할 수 있도록 설계된 강력한 도구로, 실제 사용자가 애플리케케이션과 상호작용하는 방식을 시뮬레이션합니다. 이 튜토리얼을 통해 React 컴포넌트의 동작을 검증하고, 버그를 사전에 방지하며, 리팩토링 시 안전성을 확보하는 방법을 배울 수 있습니다. 테스트 주도 개발(TDD)의 기초부터 실전 활용까지, 단계별로 명확하게 학습해보겠습니다.
기본 개념 설명
React Testing Library는 Kent C. Dodds가 만든 테스팅 라이브러리로, DOM Testing Library 위에 구축되었습니다. 기존의 Enzyme과 달리 컴포넌트의 내부 구현이 아닌 사용자 행동에 초점을 맞춥니다. 핵심 철학은 “테스트가 소프트웨어 사용 방식과 유사할수록 더 많은 신뢰를 제공한다”는 것입니다. 주요 특징으로는 DOM 쿼리 메서드(getByRole, getByText 등)를 통한 접근성 중심 테스트, 사용자 이벤트 시뮬레이션, 비동기 작업 처리 등이 있습니다. 구현 세부사항이 아닌 결과를 테스트하므로 리팩토링에 강하고, 접근성 좋은 컴포넌트 작성을 자연스럽게 유도합니다. Jest와 함께 사용되며, Create React App에는 기본으로 포함되어 있어 별도 설정 없이 바로 시작할 수 있습니다.
단계별 구현 가이드
1단계: 환경 설정
먼저 프로젝트에 필요한 패키지를 설치합니다. Create React App을 사용한다면 이미 설치되어 있지만, 직접 설정하는 경우 다음 명령어를 실행합니다:
npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event
package.json에 테스트 스크립트가 설정되어 있는지 확인하세요. "test": "jest" 또는 "test": "react-scripts test"가 있어야 합니다.
2단계: 첫 번째 테스트 작성
간단한 버튼 컴포넌트부터 시작합니다. Button.jsx와 Button.test.jsx 파일을 생성합니다. 테스트 파일에서는 render 함수로 컴포넌트를 렌더링하고, screen 객체로 요소를 찾으며, expect로 검증합니다. 기본 패턴은 Arrange(준비), Act(실행), Assert(검증)입니다.
3단계: 쿼리 메서드 이해하기
React Testing Library는 우선순위가 있는 쿼리 메서드를 제공합니다. getByRole이 가장 우선되며 접근성을 보장합니다. 버튼은 getByRole('button'), 입력 필드는 getByRole('textbox')로 찾습니다. 텍스트 콘텐츠는 getByText, 레이블은 getByLabelText를 사용합니다. getBy는 요소가 없으면 에러를 발생시키고, queryBy는 null을 반환하며, findBy는 비동기로 요소를 찾습니다.
4단계: 사용자 이벤트 시뮬레이션
@testing-library/user-event를 사용하여 실제 사용자 행동을 시뮬레이션합니다. userEvent.click()으로 클릭, userEvent.type()으로 타이핑을 재현합니다. fireEvent보다 userEvent가 더 현실적인 이벤트 시퀀스를 생성하므로 권장됩니다.
5단계: 비동기 테스트
API 호출이나 지연된 렌더링은 waitFor, findBy 쿼리로 처리합니다. await waitFor(() => expect(...)) 패턴을 사용하거나, await screen.findByText('로딩 완료')처럼 요소가 나타날 때까지 기다립니다.
실제 코드 예제와 설명
React Testing Library로 테스트 작성하기 실습을 위한 Todo 컴포넌트 예제입니다:
// TodoList.jsx
import { useState } from 'react';
function TodoList() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
if (input.trim()) {
setTodos([...todos, { id: Date.now(), text: input, completed: false }]);
setInput('');
}
};
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
return (
할 일 목록
setInput(e.target.value)}
placeholder="할 일 입력"
aria-label="할 일 입력"
/>
{todos.map(todo => (
-
toggleTodo(todo.id)}
aria-label={`${todo.text} 완료 표시`}
/>
{todo.text}
))}
);
}
export default TodoList;
// TodoList.test.jsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import TodoList from './TodoList';
test('할 일을 추가하고 완료 표시할 수 있다', async () => {
const user = userEvent.setup();
render( );
// 입력 필드와 버튼 찾기
const input = screen.getByLabelText('할 일 입력');
const button = screen.getByRole('button', { name: '추가' });
// 할 일 추가
await user.type(input, '테스트 작성하기');
await user.click(button);
// 추가된 항목 확인
expect(screen.getByText('테스트 작성하기')).toBeInTheDocument();
expect(input).toHaveValue('');
// 완료 표시
const checkbox = screen.getByLabelText('테스트 작성하기 완료 표시');
await user.click(checkbox);
expect(checkbox).toBeChecked();
expect(screen.getByText('테스트 작성하기')).toHaveStyle('text-decoration: line-through');
});
test('빈 입력은 추가되지 않는다', async () => {
const user = userEvent.setup();
render( );
const button = screen.getByRole('button', { name: '추가' });
await user.click(button);
const listItems = screen.queryAllByRole('listitem');
expect(listItems).toHaveLength(0);
});
이 예제는 사용자 관점에서 테스트하는 방법을 보여줍니다. aria-label을 통해 접근성을 확보하고, userEvent로 실제 상호작용을 시뮬레이션하며, 기대하는 동작을 명확하게 검증합니다.
고급 활용 방법
커스텀 렌더 함수: Redux나 Context Provider가 필요한 경우 래퍼를 만듭니다. render 함수를 확장하여 모든 테스트에서 공통 프로바이더를 자동으로 적용할 수 있습니다.
MSW로 API 모킹: Mock Service Worker를 사용하면 실제 네트워크 요청을 인터셉트하여 응답을 제어할 수 있습니다. fetch나 axios 호출을 테스트할 때 유용합니다.
접근성 테스트: jest-axe를 통합하여 자동으로 접근성 문제를 감지합니다. expect(await axe(container)).toHaveNoViolations()로 검증합니다.
스냅샷 테스트 최소화: 구현 세부사항 변경에 취약하므로 중요한 구조만 스냅샷으로 저장합니다. 대신 특정 동작과 결과를 명시적으로 테스트하는 것이 좋습니다.
테스트 격리: 각 테스트는 독립적이어야 합니다. beforeEach로 초기 상태를 설정하고, 테스트 간 데이터 공유를 피합니다.
마무리 및 추가 학습 자료
React Testing Library로 테스트 작성하기를 마스터하면 더 안정적이고 유지보수하기 쉬운 애플리케이션을 만들 수 있습니다. 핵심은 사용자 관점에서 생각하고, 구현이 아닌 동작을 테스트하는 것입니다. 공식 문서(testing-library.com)에서 더 많은 예제와 Best Practices를 확인하세요. Kent C. Dodds의 블로그와 Testing JavaScript 강의도 추천합니다. 실제 프로젝트에 적용하면서 경험을 쌓는 것이 가장 효과적인 학습 방법입니다. 지금 바로 여러분의 컴포넌트에 첫 테스트를 작성해보세요!
📚 함께 읽으면 좋은 글
React Hooks 실전 활용 가이드 – 초보자도 쉽게 따라하는 완벽 가이드
📅 2025. 10. 23.
🎯 React Hooks 실전 활용 가이드
React 컴포넌트 설계 패턴 – 초보자도 쉽게 따라하는 완벽 가이드
📅 2025. 10. 23.
🎯 React 컴포넌트 설계 패턴
React Hooks 실전 활용 가이드 – 초보자도 쉽게 따라하는 완벽 가이드
📅 2025. 10. 21.
🎯 React Hooks 실전 활용 가이드
React Router 실전 사용법 – 초보자도 쉽게 따라하는 완벽 가이드
📅 2025. 10. 20.
🎯 React Router 실전 사용법
React Context API 마스터하기 – 초보자도 쉽게 따라하는 완벽 가이드
📅 2025. 10. 19.
🎯 React Context API 마스터하기
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
React Testing Library로 테스트 작성하기 관련해서 궁금한 점이 더 있으시다면 언제든 물어보세요!
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 React 튜토리얼부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!