개발/React

[고급반] Step 4-1. 테스트와 안정성: Jest와 RTL로 견고한 컴포넌트 만들기

ophelisis 2025. 12. 23. 14:07
반응형

리액트 고급 과정의 마지막 단계는 안정성입니다. 아무리 멋진 기능을 만들어도, 코드 한 줄 수정했을 때 다른 기능이 깨진다면 좋은 소프트웨어라고 할 수 없습니다.

리액트 생태계의 표준 테스트 도구인 Jest와 **React Testing Library(RTL)**를 사용해, 사용자의 관점에서 컴포넌트를 검증하는 방법을 배워봅시다.


1. 🧪 왜 React Testing Library(RTL)인가?

과거에는 컴포넌트의 내부 상태(state)나 메서드를 테스트하는 방식(Enzyme 등)이 유행했습니다. 하지만 RTL은 철학이 다릅니다.

  • 사용자 중심 테스트: "내부 상태가 어떻게 변했는가"가 아니라, **"사용자에게 이 버튼이 보이는가? 클릭했을 때 화면이 바뀌는가?"**를 테스트합니다.
  • 리팩토링에 내성: 내부 구현을 바꿔도 사용자가 보는 결과가 같다면 테스트는 통과해야 합니다. RTL은 이를 가능하게 해줍니다.

2. 🛠️ 테스트의 기본 구조: AAA 패턴

모든 테스트 코드는 다음 세 단계로 구성하면 가독성이 좋아집니다.

  1. Arrange (준비): 테스트할 컴포넌트를 렌더링하고 필요한 데이터를 준비합니다.
  2. Act (실행): 클릭, 타이핑 등 사용자의 행동을 시뮬레이션합니다.
  3. 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은 요소를 찾는 다양한 쿼리를 제공합니다. 우선순위에 따라 사용하는 것이 좋습니다.

  1. getByRole: (최우선) 버튼, 링크, 헤딩 등 접근성(Accessibility)을 기반으로 요소를 찾습니다.
  2. getByLabelText / getByPlaceholderText: 폼 요소에 적합합니다.
  3. getByText: 텍스트 내용으로 찾습니다.
  4. 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%를 달성하겠다"는 목표는 때로 독이 됩니다.

  • 핵심 로직 우선: 모든 작은 컴포넌트를 테스트하기보다, 복잡한 비즈니스 로직이 담긴 커스텀 훅이나 주요 페이지 단위의 테스트를 우선하세요.
  • 통합 테스트의 가치: 개별 컴포넌트 테스트도 중요하지만, 여러 컴포넌트가 협력하는 '통합 테스트'가 실제 버그를 더 잘 잡아냅니다.
반응형