1. TDD란 무엇인가?
테스트 주도 개발(Test-Driven Development, TDD)은 소프트웨어 개발 방법론 중 하나로, 실제 코드를 작성하기 전에 테스트 코드를 먼저 작성하는 방식입니다. TDD의 기본 사이클은 다음과 같습니다:
- 실패하는 테스트 작성 (Red)
- 테스트를 통과하는 최소한의 코드 작성 (Green)
- 코드 리팩토링 (Refactor)
이 과정을 "Red-Green-Refactor" 사이클이라고 부릅니다.
2. React에서 TDD를 적용하는 이유
React 애플리케이션에 TDD를 적용하면 다음과 같은 이점이 있습니다:
- 버그 조기 발견 및 수정
- 코드의 품질과 신뢰성 향상
- 리팩토링 시 안전성 확보
- 명확한 요구사항 정의 및 구현
3. React TDD 도구
React 애플리케이션의 TDD를 위해 주로 사용되는 도구들은 다음과 같습니다:
- Jest: Facebook에서 만든 JavaScript 테스트 프레임워크
- React Testing Library: React 컴포넌트를 테스트하기 위한 라이브러리
- Enzyme: Airbnb에서 만든 React 컴포넌트 테스트 도구 (최근에는 React Testing Library를 더 많이 사용하는 추세)
4. React TDD 실습
간단한 카운터 컴포넌트를 TDD 방식으로 개발해보겠습니다.
4.1 실패하는 테스트 작성 (Red)
먼저, Counter 컴포넌트에 대한 테스트를 작성합니다.
// Counter.test.js
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('Counter가 0부터 시작하고 증가 버튼을 누르면 1이 된다', () => {
const { getByText } = render(<Counter />);
expect(getByText('0')).toBeInTheDocument();
fireEvent.click(getByText('증가'));
expect(getByText('1')).toBeInTheDocument();
});
이 테스트를 실행하면 당연히 실패합니다. Counter 컴포넌트가 아직 없기 때문입니다.
4.2 테스트를 통과하는 최소한의 코드 작성 (Green)
이제 테스트를 통과할 수 있는 최소한의 코드를 작성합니다.
// Counter.js
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<span>{count}</span>
<button onClick={() => setCount(count + 1)}>증가</button>
</div>
);
}
export default Counter;
이제 테스트를 다시 실행하면 통과할 것입니다.
4.3 코드 리팩토링 (Refactor)
현재 코드는 이미 간단하지만, 실제 프로젝트에서는 이 단계에서 코드를 개선합니다. 예를 들어, 스타일을 적용하거나 더 복잡한 로직을 추가할 수 있습니다.
5. 복잡한 컴포넌트에 대한 TDD
실제 프로젝트에서는 더 복잡한 컴포넌트를 다루게 됩니다. 예를 들어, API 호출이 필요한 컴포넌트를 TDD로 개발해보겠습니다.
5.1 실패하는 테스트 작성 (Red)
// UserList.test.js
import React from 'react';
import { render, waitFor } from '@testing-library/react';
import UserList from './UserList';
// API 호출을 모킹
jest.mock('../api', () => ({
fetchUsers: jest.fn(() => Promise.resolve([{ id: 1, name: 'John Doe' }]))
}));
test('UserList가 사용자 목록을 표시한다', async () => {
const { getByText } = render(<UserList />);
await waitFor(() => {
expect(getByText('John Doe')).toBeInTheDocument();
});
});
5.2 테스트를 통과하는 최소한의 코드 작성 (Green)
// UserList.js
import React, { useState, useEffect } from 'react';
import { fetchUsers } from '../api';
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetchUsers().then(setUsers);
}, []);
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
export default UserList;
5.3 코드 리팩토링 (Refactor)
이 단계에서는 에러 처리, 로딩 상태 표시 등을 추가할 수 있습니다.
6. TDD의 장단점
장점:
- 높은 코드 품질과 신뢰성
- 명확한 요구사항 정의
- 리팩토링 용이성
- 테스트 문서화 효과
단점:
- 초기 개발 속도가 느릴 수 있음
- 학습 곡선이 있음
- 모든 상황에 적합하지 않을 수 있음 (예: 프로토타이핑)
React에서의 TDD는 높은 품질의 코드를 작성하는 데 도움이 되는 강력한 방법론입니다. 초기에는 시간이 더 걸릴 수 있지만, 장기적으로는 유지보수가 쉽고 버그가 적은 애플리케이션을 만드는 데 도움이 됩니다.
TDD를 시작할 때는 작은 컴포넌트부터 시작하여 점진적으로 복잡한 컴포넌트로 확장해 나가는 것이 좋습니다. 또한, 팀 전체가 TDD 방식에 동의하고 실천하는 것이 중요합니다.
React와 TDD를 함께 사용하면, 더 견고하고 유지보수가 쉬운 웹 애플리케이션을 개발할 수 있습니다. 여러분의 다음 React 프로젝트에서 TDD를 시도해보는 것은 어떨까요?