반응형
리액트 고급 과정의 마지막 단계는 안정성입니다. 아무리 멋진 기능을 만들어도, 코드 한 줄 수정했을 때 다른 기능이 깨진다면 좋은 소프트웨어라고 할 수 없습니다.
리액트 생태계의 표준 테스트 도구인 Jest와 **React Testing Library(RTL)**를 사용해, 사용자의 관점에서 컴포넌트를 검증하는 방법을 배워봅시다.
1. 🧪 왜 React Testing Library(RTL)인가?
과거에는 컴포넌트의 내부 상태(state)나 메서드를 테스트하는 방식(Enzyme 등)이 유행했습니다. 하지만 RTL은 철학이 다릅니다.
- 사용자 중심 테스트: "내부 상태가 어떻게 변했는가"가 아니라, **"사용자에게 이 버튼이 보이는가? 클릭했을 때 화면이 바뀌는가?"**를 테스트합니다.
- 리팩토링에 내성: 내부 구현을 바꿔도 사용자가 보는 결과가 같다면 테스트는 통과해야 합니다. RTL은 이를 가능하게 해줍니다.
2. 🛠️ 테스트의 기본 구조: AAA 패턴
모든 테스트 코드는 다음 세 단계로 구성하면 가독성이 좋아집니다.
- Arrange (준비): 테스트할 컴포넌트를 렌더링하고 필요한 데이터를 준비합니다.
- Act (실행): 클릭, 타이핑 등 사용자의 행동을 시뮬레이션합니다.
- Assert (단언): 기대하는 결과가 화면에 나타났는지 확인합니다.
🛠️ 간단한 예시: 카운터 테스트
JavaScript
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('더하기 버튼을 누르면 숫자가 1 증가한다', () => {
// 1. Arrange
render(<Counter />);
const button = screen.getByRole('button', { name: /plus/i });
const countDisplay = screen.getByTestId('count');
// 2. Act
fireEvent.click(button);
// 3. Assert
expect(countDisplay).toHaveTextContent('1');
});
3. 🔍 좋은 쿼리(Query) 선택하기
RTL은 요소를 찾는 다양한 쿼리를 제공합니다. 우선순위에 따라 사용하는 것이 좋습니다.
- getByRole: (최우선) 버튼, 링크, 헤딩 등 접근성(Accessibility)을 기반으로 요소를 찾습니다.
- getByLabelText / getByPlaceholderText: 폼 요소에 적합합니다.
- getByText: 텍스트 내용으로 찾습니다.
- getByTestId: (최후의 수단) 위 방법으로 찾기 어려울 때 사용합니다.
4. 🌐 비동기 컴포넌트 테스트 (findBy)
API 호출이 포함된 컴포넌트는 데이터가 올 때까지 기다려야 합니다. 이때는 findBy 쿼리와 async/await를 사용합니다.
JavaScript
test('사용자 목록이 로딩 후 화면에 표시된다', async () => {
render(<UserList />);
// 데이터가 로딩되어 화면에 나타날 때까지 기다립니다 (기본 1000ms)
const userItem = await screen.findByText('John Doe');
expect(userItem).toBeInTheDocument();
});
5. 💡 시니어의 조언: 테스트 커버리지보다 중요한 것
"커버리지 100%를 달성하겠다"는 목표는 때로 독이 됩니다.
- 핵심 로직 우선: 모든 작은 컴포넌트를 테스트하기보다, 복잡한 비즈니스 로직이 담긴 커스텀 훅이나 주요 페이지 단위의 테스트를 우선하세요.
- 통합 테스트의 가치: 개별 컴포넌트 테스트도 중요하지만, 여러 컴포넌트가 협력하는 '통합 테스트'가 실제 버그를 더 잘 잡아냅니다.
반응형
'개발 > React' 카테고리의 다른 글
| [고급반] Step 4-3. TDD(테스트 주도 개발): 견고한 UI를 만드는 실전 워크플로우 (0) | 2025.12.23 |
|---|---|
| [고급반] Step 4-2. 클린 아키텍처: 관심사 분리와 계층 설계 (0) | 2025.12.23 |
| [고급반] Step 3-3. React Server Components(RSC): 클라이언트와 서버의 경계 허물기 (0) | 2025.12.23 |
| [고급반] Step 3-2. Suspense와 Error Boundary: 선언적 비동기 처리 아키텍처 (0) | 2025.12.23 |
| [고급반] Step 3-1. Concurrent React: useTransition과 useDeferredValue (0) | 2025.12.23 |