React · 2025-12-17

React 테스트 전략: RTL과 Jest로 안정적 컴포넌트 검증

React Testing Library와 Jest를 기반으로 리액트 컴포넌트 테스트 개념, 설정 과정, 예제 중심 코드와 모킹/비동기 처리 방법을 정리한 기술 자료

작성일 : 2025-12-17 ㆍ 작성자 : 관리자
post
목차

개요

리액트 애플리케이션의 테스트는 유지보수성과 신뢰성을 높인다. 본문은 React Testing Library(RTL)와 Jest를 이용한 실전형 접근을 설명한다. 초보자도 이해하기 쉬운 단계별 예제와 함께 jest react 테스트 설정과 react testing library 예제 중심의 설명을 제공한다.

왜 React Testing Library와 Jest를 선택할까

Jest는 빠른 테스트 러너이자 풍부한 기능을 제공한다. 스냅샷, 모킹, 커버리지 기능이 내장되어 있다. React Testing Library는 사용자 관점의 테스트를 장려한다. DOM 접근을 최소화하고 실제 사용 흐름을 검증하는 데 유리하다. 두 도구의 조합은 리액트 컴포넌트 테스트 방법에서 표준으로 자리잡고 있다.

환경 설정

필수 패키지 설치

npm install --save-dev jest @testing-library/react @testing-library/jest-dom @testing-library/user-event babel-jest

프로젝트에 따라 TypeScript, babel 설정이 추가될 수 있다. Create React App은 기본적으로 Jest를 포함하므로 별도 설정이 적다.

Jest 초기 설정 예시

{
  "scripts": {
    "test": "jest"
  },
  "jest": {
    "testEnvironment": "jsdom",
    "setupFilesAfterEnv": ["@testing-library/jest-dom/extend-expect"]
  }
}

위 설정은 jest react 테스트 설정의 기본 골격이다. setupFilesAfterEnv로 jest-dom 커스텀 매처를 등록한다.

기본 컴포넌트 테스트 예제

간단한 카운터 컴포넌트를 만들어 테스트한다. 컴포넌트는 버튼 클릭으로 증가한다.

Counter 컴포넌트

// Counter.jsx
import React, { useState } from 'react';

export default function Counter({ initial = 0 }) {
  const [count, setCount] = useState(initial);
  return (
    <div>
      <span data-testid="count">{count}</span>
      <button onClick={() => setCount(c => c + 1)}>증가</button>
    </div>
  );
}

테스트 코드

// Counter.test.jsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

test('초기값을 표시하고 버튼 클릭으로 증가한다', async () => {
  render(<Counter initial={0} />);
  const count = screen.getByTestId('count');
  const button = screen.getByRole('button', { name: /증가/i });

  expect(count).toHaveTextContent('0');
  await userEvent.click(button);
  expect(count).toHaveTextContent('1');
});

위 테스트는 사용자 행위를 시뮬레이션하고 DOM의 변화를 검증한다. react testing library 예제로 적합하다.

비동기와 API 호출 테스트

비동기 작업은 모킹을 통해 안정적으로 테스트한다. fetch나 axios 호출을 jest로 모킹한다.

비동기 컴포넌트 예시

// UserList.jsx
import React, { useEffect, useState } from 'react';

export default function UserList({ api }) {
  const [users, setUsers] = useState([]);
  useEffect(() => {
    let mounted = true;
    api.getUsers().then(data => {
      if (mounted) setUsers(data);
    });
    return () => { mounted = false; };
  }, [api]);
  return (
    <ul>
      {users.map(u => <li key={u.id}>{u.name}</li>)}
    </ul>
  );
}

비동기 테스트

// UserList.test.jsx
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import UserList from './UserList';

test('API에서 사용자 목록을 받아 렌더링한다', async () => {
  const fakeApi = { getUsers: jest.fn().mockResolvedValue([{ id: 1, name: 'Alice' }]) };
  render(<UserList api={fakeApi} />);
  await waitFor(() => expect(screen.getByText('Alice')).toBeInTheDocument());
});

waitFor는 비동기 DOM 변화를 기다린다. mockResolvedValue로 API 응답을 제어하면 네트워크 의존성을 제거할 수 있다.

모킹 전략과 의존성 분리

의존성을 주입하거나 jest.mock을 사용해 외부 모듈을 대체한다. 이렇게 하면 테스트가 예측 가능해진다. 컴포넌트 내부에서 직접 fetch를 호출하면 테스트가 복잡해진다.

테스트 구조와 베스트 프랙티스

  • 사용자 관점의 검증을 우선시한다. DOM 내부 구현에 의존하지 않는다.
  • 작은 단위의 테스트를 작성해 원인 파악을 쉽게 만든다.
  • 비동기 코드는 waitFor나 findBy를 사용해 안정적으로 검사한다.
  • 외부 API는 모킹하고 네트워크 호출은 제거한다.
  • 테스트 커버리지는 참고 지표로 사용하되, 의미 있는 커버리지를 목표로 한다.

마무리

이 글은 jest react 테스트 설정부터 react testing library 예제까지 주요 포인트를 다뤘다. 리액트 컴포넌트 테스트 방법은 사용자 관점의 검증, 의존성 분리, 비동기 처리에 집중하면 효과적이다. 꾸준한 테스트 작성은 코드 품질과 개발 속도에 긍정적 영향을 준다.

react testing library 예제 jest react 테스트 설정 리액트 컴포넌트 테스트 방법 react testing library jest 리액트 테스트 컴포넌트 테스트 테스트 커버리지