본문 바로가기
JavaScript/React

React 테스트 코드 작성: React Testing Library와 Jest 활용

by GangDev 2024. 3. 26.

 

React에서 테스트 코드를 작성할 때 사용되는 툴로는 React Testing Libaray와 Jest 가 있다.
React Testing Library는 React 컴포넌트를 테스트하는 데 집중된 라이브러리이고, 리액트 컴포넌트 테스팅을 위한 가상 돔(Virtual DOM)을 제공해준다. 핵심은 가능한 한 사용자와 같은 방식으로 컴포넌트와 상호작용하며 테스트하는 것이다.(테스트 중심 개발인 TDD 접근 방식에 부합함)
Jst는 test runner(테스트를 실행하도록 해줌)로, 테스트를 찾아서 실행하여 해당 테스트의 통과 여부를 결정하는 JavaScript 테스팅 프레임워크이다.

 

React Testing Library 특징 >>

컴포넌트의 내부 구현보단 사용자가 보고 상호작용하는 인터페이스에 집중한다.
getBy, findBy, queryBy 등의 쿼리를 제공하여 DOM 요소를 찾을 수 있다.
사용자 이벤트를 모의할 수 있는 fireEvent 함수를 제공한다.

 

예시:

// Button.js
import React from 'react';

const Button = ({ onClick, children }) => (
  <button onClick={onClick}>{children}</button>
);

export default Button;

 

위의 버튼 컴포넌트에 대한 테스트 코드는 아래와 같다.

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

test('버튼 클릭 시 함수가 호출됩니다', () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick}>클릭하세요</Button>);

  const button = screen.getByText('클릭하세요');
  fireEvent.click(button);

  expect(handleClick).toHaveBeenCalledTimes(1);
});

Button 컴포넌트가 렌더링되었을 때, 해당 버튼을 클릭하면 handleClick 함수가 한 번 호출되는지를 검증하는 코드다.

 

const handleClick = jest.fn(); :
jest.fn() 함수를 사용하여 모의 함수(mocked function)인 handleClick 을 생성한다.
이 모의 함수는 버튼이 클릭될 때 호출될 것이며, 호출 여부와 횟수 등을 추적할 수 있다.

 

render(<Button onClick={handleClick}>클릭하세요</Button>); :
React 컴포넌트인 Button 을 렌더링한다. 이 때, onClick prop으로 위에서 만든 handleClick 모의 함수를 전달한다.
따라서 이 버튼을 클릭하면 handleClick 함수가 호출될 것이다.

 

const button = screen.getByText('클릭하세요'); :
화면에서 텍스트가 '클릭하세요' 버튼을 찾아서 button 변수에 할당한다.

 

fireEvent.click(button); :
fireEvent 객체를 사용하여 button 요소를 클릭하는 시뮬레이션을 수행한다.
(실제로 버튼이 클릭되었다고 가정하고 클릭 이벤트를 발생시킨다)

 

expect(handleClick).toHaveBeenCalledTimes(1); :
expect 함수를 사용하여 handleClick 모의 함수가 한 번 호출되었는지를 검증한다.


Jest 특징 >>

 

React 프로젝트를 위한 Create React APP과 같은 도구에 이미 통합되어 있어서 별도의 설정 없이 사용할 수 있다.

 

컴포넌트의 렌더링 결과를 스냅샷으로 저장하고, 후속 테스트에서 이전 스냇샷과 비교하여 변경사항을 감지할 수 있다.

 

외부 종속성을 모킹하거나 함수 호출을 감시하는 기능을 제공한다.

 

예시 :

// Button.test.js
import React from 'react';
import renderer from 'react-test-renderer';
import Button from './Button';

test('Button 렌더링이 스냅샷과 일치하는지 확인합니다', () => {
  const component = renderer.create(<Button>클릭하세요</Button>);
  let tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});

React 컴포넌트인 Button 의 렌더링 결과가 스냅샷과 일치하는지 확인하는 테스트를 작성한 코드다.
(컴포넌트의 렌더링 결과를 스냅샷으로 캡처하고, 이후에 렌더링 결과가 변경되지 않았는지 검증)

 

renderer.create(<Button>클릭하세요</Button> :
react-test-renderer 라이브러리를 사용하여 Button 컴포넌트를 렌더링한다.
(컴포넌트를 가상 DOM에 렌더링하고 그 결과를 스냅샷으로 캡처한다)

 

let tree = component.toJSON(); :
렌더링된 컴포넌트를 가리키는 component 객체의 JSON 표현을 가져와서 tree 변수에 할당한다.
(컴포넌트의 렌더링 결과를 JSON 형태로 가져온다)

 

expect(tree).toMatchSnapshot(); :
expect 함수를 사용하여 tree 변수에 저장된 렌더링 결과와 스냅샷을 비교한다.
(스냅샷은 이전에 캡처된 렌더링 결과이다. 현재 렌더링 결과와 비교해서 일치 여부를 확인하다. 스냅샷과 일치하지 않는다면 테스트가 실패한다)


스냅샷 테스팅 하는 이유?

 

코드를 수정하거나 리팩토링할 때, UI 컴포넌트의 레이아웃이나 모양에 에상치 못한 영향을 줄 수 있다.
스냅샷 테스팅을 사용하면 이러한 변경 사항을 미리 파악하여 버그를 방지하고, 코드 변경을 안정적으로 관리할 수 있게 된다.
스냅샷을 사용하면 특정 상태에서 컴포넌트가 어떻게 렌더링되어야 하는지 정확하게 기록할 수 있다.

 

---

24년 1월 19일 작성된 글입니다