React와 TypeScript로 테스팅하기 ====

React 애플리케이션을 개발하면서, 코드의 품질을 유지하기 위해 필요한 것이 바로 테스트입니다. 특히 TypeScript를 사용하면 정적 타입 검사를 통해 더 안전하게 코드를 작성할 수 있지만, 테스트 또한 중요합니다. 이번 글에서는 React 컴포넌트를 TypeScript와 함께 테스트하는 방법에 대해 알아보겠습니다.

테스팅 라이브러리 선택하기

React 애플리케이션을 테스트하기 위해 가장 많이 사용되는 라이브러리는 Jest와 React Testing Library입니다. Jest는 테스트 프레임워크로, 스냅샷 테스트, 모의 함수(mock function) 등을 지원하며, React Testing Library는 React 컴포넌트를 사용자 관점에서 테스트할 수 있도록 도와줍니다.

먼저, 이 두 라이브러리를 설치해보겠습니다:

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

이제 기본적인 테스트 환경이 구축되었습니다.

간단한 React 컴포넌트 만들기

테스트를 위한 간단한 React 컴포넌트를 만들어 보겠습니다. 컴포넌트는 사용자의 이름을 입력받고 인사 메시지를 출력하는 기능을 가집니다.

// Greeting.tsx
import React from 'react';

interface GreetingProps {
  name: string;
}

const Greeting: React.FC<GreetingProps> = ({ name }) => {
  return <h1>Hello, {name}!</h1>;
};

export default Greeting;

위의 컴포넌트는 name이라는 prop을 받아서 인사 메시지를 출력하는 간단한 기능을 합니다.

컴포넌트 테스트하기

이제, 위의 Greeting 컴포넌트를 테스트해보겠습니다. React Testing Library를 사용하여 컴포넌트를 렌더링하고, 사용자 상호작용을 테스트할 수 있습니다.

// Greeting.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import Greeting from './Greeting';

test('renders greeting message', () => {
  render(<Greeting name="John" />);
  
  const greetingElement = screen.getByText(/Hello, John!/i);
  expect(greetingElement).toBeInTheDocument();
});

위의 테스트 코드에서는 Greeting 컴포넌트를 렌더링한 후, 특정 텍스트가 문서에 있는지 확인합니다. screen.getByText 함수를 사용하여 사용자가 볼 수 있는 텍스트를 찾고, expect로 해당 요소가 존재하는지 체크합니다.

이벤트 테스트하기

이제 이벤트가 발생했을 때의 동작을 테스트해보겠습니다. 예를 들어, 버튼 클릭 시 이름을 입력받아 인사 메시지를 업데이트하는 기능을 추가하겠습니다.

// GreetingWithButton.tsx
import React, { useState } from 'react';

const GreetingWithButton: React.FC = () => {
  const [name, setName] = useState<string>('');
  
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setName(event.target.value);
  };

  return (
    <div>
      <input type="text" onChange={handleChange} placeholder="Enter your name" />
      <button onClick={() => alert(Hello, ${name}!)}>Greet</button>
      <h1>Hello, {name}!</h1>
    </div>
  );
};

export default GreetingWithButton;

이제 이 컴포넌트를 테스트해보겠습니다.

// GreetingWithButton.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import GreetingWithButton from './GreetingWithButton';

test('updates greeting message on input change and button click', () => {
  render(<GreetingWithButton />);
  
  const inputElement = screen.getByPlaceholderText(/Enter your name/i);
  const buttonElement = screen.getByText(/Greet/i);
  
  fireEvent.change(inputElement, { target: { value: 'Alice' } });
  expect(screen.getByText(/Hello, Alice!/i)).toBeInTheDocument();
  
  fireEvent.click(buttonElement);
  expect(window.alert).toHaveBeenCalledWith('Hello, Alice!');
});

위의 테스트에서는 먼저 입력 필드에 값을 입력하고, 그에 따라 화면의 인사 메시지가 업데이트되는지 확인합니다. 또한 버튼 클릭 시 alert가 호출되는지 테스트합니다.

마무리

이 글에서는 React와 TypeScript를 사용하여 간단한 컴포넌트를 만들고, 그 컴포넌트를 테스트하는 방법에 대해 알아보았습니다. React Testing Library를 통해 사용자 경험에 기반한 테스트 작성이 가능하며, TypeScript의 정적 타입 검사를 통해 더욱 안정적인 코드를 작성할 수 있습니다. 테스트는 애플리케이션의 품질을 높이는 데 중요한 역할을 하므로, 적극적으로 활용해보세요.