React Testing Library로 테스트 작성하기 – 초보자도 쉽게 따라하는 완벽 가이드

React Testing Library로 테스트 작성하기 – 초보자도 쉽게 따라하는 완벽 가이드

1. 도입 – 학습 목표 및 필요성

React Testing Library로 테스트 작성하기는 현대 프론트엔드 개발에서 필수적인 스킬입니다. 이 가이드를 통해 여러분은 사용자 중심의 테스트를 작성하는 방법을 배우게 됩니다. React Testing Library는 실제 사용자가 애플리케이션과 상호작용하는 방식으로 컴포넌트를 테스트할 수 있도록 설계되었습니다. 이를 통해 더 신뢰할 수 있는 코드를 작성하고, 버그를 조기에 발견하며, 리팩토링에 대한 자신감을 가질 수 있습니다. 본 튜토리얼에서는 기본 개념부터 고급 활용 방법까지 단계별로 학습하여, 실무에서 바로 적용할 수 있는 테스트 작성 능력을 갖추게 됩니다.

2. 기본 개념 설명

React Testing Library는 DOM Testing Library를 기반으로 하는 가벼운 테스팅 도구입니다. 기존의 Enzyme과 달리, 컴포넌트의 내부 구현보다는 사용자 관점에서의 동작에 집중합니다. 핵심 철학은 “테스트가 소프트웨어 사용 방식과 유사할수록 더 신뢰할 수 있다”는 것입니다.

주요 특징은 다음과 같습니다:

  • 접근성 우선: getByRole, getByLabelText 같은 쿼리를 통해 접근성을 고려한 테스트 작성
  • 구현 세부사항 숨기기: state나 props 직접 접근 대신 렌더링 결과로 검증
  • 비동기 처리: waitFor, findBy 쿼리로 비동기 작업 간편하게 테스트
  • Jest와 완벽한 통합: Create React App에 기본 포함되어 즉시 사용 가능

React Testing Library로 테스트 작성하기를 시작하기 전에 Jest의 기본 문법(describe, it, expect)과 React 컴포넌트 구조에 대한 이해가 필요합니다.

3. 단계별 구현 가이드

3.1 환경 설정

먼저 프로젝트에 필요한 패키지를 설치합니다. Create React App을 사용하는 경우 이미 설치되어 있습니다.

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

setupTests.js 파일에서 jest-dom을 import하여 추가적인 매처를 사용할 수 있습니다:

import '@testing-library/jest-dom';

3.2 첫 번째 테스트 작성

간단한 버튼 컴포넌트를 테스트해봅시다. 테스트는 다음 단계로 진행됩니다:

  1. 렌더링: render 함수로 컴포넌트를 가상 DOM에 렌더링
  2. 요소 선택: 쿼리 함수로 테스트할 요소 찾기
  3. 상호작용: userEvent로 사용자 액션 시뮬레이션
  4. 검증: expect와 매처로 결과 확인

3.3 쿼리 우선순위 이해

React Testing Library는 쿼리 사용에 우선순위를 권장합니다:

  • 1순위: getByRole, getByLabelText – 접근성을 고려한 쿼리
  • 2순위: getByPlaceholderText, getByText – 사용자가 보는 텍스트
  • 3순위: getByDisplayValue – 폼 요소의 현재 값
  • 최후: getByTestId – 다른 방법이 없을 때만 사용

쿼리 변형도 이해해야 합니다:

  • getBy: 즉시 요소를 찾고, 없으면 에러 발생
  • queryBy: 요소를 찾고, 없으면 null 반환 (존재하지 않음 검증용)
  • findBy: 비동기로 요소를 찾음 (Promise 반환)

3.4 비동기 테스트 처리

API 호출이나 타이머 같은 비동기 작업은 waitFor나 findBy를 사용합니다. findBy는 내부적으로 waitFor와 getBy를 조합한 것입니다. 비동기 테스트에서는 async/await 패턴을 사용하며, 기본 타임아웃은 1000ms입니다.

3.5 사용자 이벤트 시뮬레이션

fireEvent 대신 @testing-library/user-event를 사용하는 것이 권장됩니다. userEvent는 실제 브라우저 동작을 더 정확하게 시뮬레이션합니다. 예를 들어 type 메서드는 keyDown, keyPress, keyUp 이벤트를 모두 발생시킵니다.

4. 실제 코드 예제와 설명

예제 1: 카운터 컴포넌트 테스트

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

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    

카운트: {count}

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

describe('Counter 컴포넌트', () => {
  it('초기 카운트가 0으로 표시된다', () => {
    render();
    expect(screen.getByText('카운트: 0')).toBeInTheDocument();
  });
  
  it('증가 버튼 클릭 시 카운트가 증가한다', async () => {
    const user = userEvent.setup();
    render();
    
    const increaseButton = screen.getByRole('button', { name: '증가' });
    await user.click(increaseButton);
    
    expect(screen.getByText('카운트: 1')).toBeInTheDocument();
  });
  
  it('감소 버튼 클릭 시 카운트가 감소한다', async () => {
    const user = userEvent.setup();
    render();
    
    const decreaseButton = screen.getByRole('button', { name: '감소' });
    await user.click(decreaseButton);
    
    expect(screen.getByText('카운트: -1')).toBeInTheDocument();
  });
});

예제 2: 비동기 데이터 로딩 테스트

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

// API 모킹
global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve([
      { id: 1, name: '홍길동' },
      { id: 2, name: '김철수' }
    ])
  })
);

test('사용자 목록이 로딩 후 표시된다', async () => {
  render();
  
  // 로딩 중 표시 확인
  expect(screen.getByText('로딩 중...')).toBeInTheDocument();
  
  // 비동기로 데이터 로딩 대기
  const user1 = await screen.findByText('홍길동');
  expect(user1).toBeInTheDocument();
  
  // 로딩 메시지가 사라졌는지 확인
  expect(screen.queryByText('로딩 중...')).not.toBeInTheDocument();
});

5. 고급 활용 방법

5.1 커스텀 렌더 함수

Redux, React Router, Theme Provider 같은 공통 Provider를 매번 감싸는 대신 커스텀 렌더 함수를 만들 수 있습니다:

// test-utils.jsx
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';
import { store } from './store';

function renderWithProviders(ui, options) {
  return render(
    {ui},
    options
  );
}

export * from '@testing-library/react';
export { renderWithProviders as render };

5.2 테스트 격리와 클린업

각 테스트 전후로 상태를 초기화하려면 beforeEach와 afterEach를 사용합니다. React Testing Library는 자동으로 cleanup을 수행하지만, 모킹한 함수는 수동으로 초기화해야 합니다:

beforeEach(() => {
  jest.clearAllMocks();
});

5.3 스냅샷 테스트 통합

React Testing Library로 테스트 작성하기에서는 스냅샷 테스트보다 명시적 assertion을 권장하지만, UI 변경 감지가 필요한 경우 함께 사용할 수 있습니다.

6. 마무리 및 추가 학습 자료

React Testing Library로 테스트 작성하기를 마스터하면 더 안정적이고 유지보수하기 쉬운 React 애플리케이션을 개발할 수 있습니다. 핵심은 사용자 관점에서 생각하고, 구현 세부사항이 아닌 동작을 테스트하는 것입니다.

추가 학습 자료:

  • 공식 문서: testing-library.com/react
  • Common Mistakes 가이드: 흔한 실수와 해결 방법
  • Kent C. Dodds 블로그: Testing Library 창시자의 베스트 프랙티스
  • 실전 프로젝트: 기존 프로젝트에 테스트를 점진적으로 추가해보세요

지금 바로 여러분의 프로젝트에 첫 번째 테스트를 작성해보세요. 작은 컴포넌트부터 시작하면 테스트 작성이 자연스러워질 것입니다!

📚 함께 읽으면 좋은 글

1

React Context API 마스터하기 – 초보자도 쉽게 따라하는 완벽 가이드

📂 React 튜토리얼
📅 2025. 11. 11.
🎯 React Context API 마스터하기

2

React 컴포넌트 설계 패턴 – 초보자도 쉽게 따라하는 완벽 가이드

📂 React 튜토리얼
📅 2025. 11. 10.
🎯 React 컴포넌트 설계 패턴

3

React 컴포넌트 설계 패턴 – 초보자도 쉽게 따라하는 완벽 가이드

📂 React 튜토리얼
📅 2025. 11. 9.
🎯 React 컴포넌트 설계 패턴

4

React Hooks 실전 활용 가이드 – 초보자도 쉽게 따라하는 완벽 가이드

📂 React 튜토리얼
📅 2025. 11. 9.
🎯 React Hooks 실전 활용 가이드

5

React Hooks 실전 활용 가이드 – 초보자도 쉽게 따라하는 완벽 가이드

📂 React 튜토리얼
📅 2025. 11. 7.
🎯 React Hooks 실전 활용 가이드

💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!

📢 이 글이 도움되셨나요? 공유해주세요!

여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨

🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏

💬 여러분의 소중한 의견을 들려주세요!

여러분은 React Testing Library로 테스트 작성하기에 대해 어떻게 생각하시나요?

💡
유용한 정보 공유

궁금한 점 질문

🤝
경험담 나누기

👍
의견 표현하기

⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨

🔔 블로그 구독하고 최신 글을 받아보세요!

📚
다양한 주제
17개 카테고리

정기 업데이트
하루 3회 발행

🎯
실용적 정보
바로 적용 가능

💡
최신 트렌드
2025년 기준

🌟 React 튜토리얼부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨

📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!

답글 남기기