소프트웨어 개발에서 Test-Driven Development(TDD)는 안정성과 유지 보수성을 높이는 강력한 방법론으로 자리 잡았습니다. 특히 React와 같은 UI 라이브러리에서는 컴포넌트 기반 아키텍처와 TDD가 자연스럽게 잘 어우러집니다. 이 글에서는 React 프로젝트에 TDD를 적용하는 방법을 단계별로 알아보고, TDD를 통해 얻을 수 있는 이점과 함께 실제 개발 시의 팁을 제공합니다.
TDD란 무엇인가?
TDD는 테스트 주도 개발(Test-Driven Development)의 약자로, 코드를 작성하기 전에 테스트를 먼저 작성하는 소프트웨어 개발 방법론입니다. TDD는 다음과 같은 세 단계로 이루어집니다:
- Red: 실패하는 테스트를 작성합니다. (코드가 아직 없기 때문에 실패해야 합니다.)
- Green: 테스트를 통과하는 최소한의 코드를 작성합니다.
- Refactor: 코드를 리팩터링하여 품질을 개선하고 중복을 제거합니다. 테스트는 계속 통과해야 합니다.
이 과정을 반복하며, 코드는 테스트로 검증되고 점진적으로 개선됩니다.
TDD가 React 개발에 적합한 이유
React는 컴포넌트 기반 라이브러리로, 각 컴포넌트가 명확한 역할을 가지며 재사용 가능하도록 설계됩니다. 이러한 특성은 TDD의 세부적인 테스트 접근법과 잘 맞아떨어집니다. 주요 이유는 다음과 같습니다:
- 컴포넌트 단위 테스트: React 컴포넌트는 작은 단위로 나눠지기 때문에 TDD로 테스트를 작성하기 용이합니다.
- UI와 비즈니스 로직 분리: TDD를 통해 UI 컴포넌트와 로직을 테스트하면서 각각의 역할을 명확히 구분할 수 있습니다.
- 안정성 확보: React 애플리케이션은 상태 관리와 사용자 이벤트 처리에 민감합니다. TDD를 통해 불안정한 코드와 오류를 사전에 방지할 수 있습니다.
TDD 환경 설정
React에서 TDD를 적용하기 위해 필요한 기본 환경을 설정해보겠습니다.
1. 프로젝트 생성 및 기본 설정
React 프로젝트를 생성하고 필요한 의존성을 설치합니다:
npx create-react-app tdd-example --template typescript
cd tdd-example
2. 테스트 라이브러리 설치
React에는 기본적으로 Jest와 React Testing Library가 포함되어 있습니다. 추가적인 설정이 필요하지 않지만, 이외의 라이브러리가 필요한 경우 설치합니다:
npm install --save-dev @testing-library/react @testing-library/jest-dom
3. 테스트 스크립트 실행 확인
package.json에 설정된 테스트 명령어를 실행하여 환경이 제대로 구성되었는지 확인합니다:
npm test
React에서 TDD를 적용하는 단계
React 컴포넌트를 TDD 방식으로 개발하는 구체적인 과정을 알아보겠습니다. 예제로 간단한 "할 일 목록(To-Do List)" 애플리케이션을 만들어 보겠습니다.
1. 요구 사항 정의
할 일 목록 애플리케이션의 요구 사항은 다음과 같습니다:
- 사용자는 새로운 할 일을 입력할 수 있어야 합니다.
- 입력된 할 일은 목록에 표시됩니다.
- 사용자는 할 일을 완료 상태로 표시할 수 있어야 합니다.
2. 실패하는 테스트 작성 (Red 단계)
첫 번째 요구 사항인 "사용자가 새로운 할 일을 입력할 수 있어야 한다"를 테스트합니다. App.test.tsx 파일을 작성합니다:
import { render, screen, fireEvent } from "@testing-library/react";
import App from "./App";
test("새로운 할 일을 추가할 수 있다", () => {
render(<App />);
const input = screen.getByPlaceholderText("할 일을 입력하세요");
const button = screen.getByText("추가");
fireEvent.change(input, { target: { value: "React 배우기" } });
fireEvent.click(button);
expect(screen.getByText("React 배우기")).toBeInTheDocument();
});
이 테스트는 아직 작성되지 않은 UI와 동작을 기반으로 합니다. 따라서 실행하면 실패합니다.
3. 최소한의 코드 작성 (Green 단계)
테스트를 통과시키기 위해 최소한의 코드를 작성합니다. App.tsx를 아래와 같이 구현합니다:
import React, { useState } from "react";
const App = () => {
const [todos, setTodos] = useState<string[]>([]);
const [input, setInput] = useState("");
const addTodo = () => {
setTodos([...todos, input]);
setInput("");
};
return (
<div>
<input
placeholder="할 일을 입력하세요"
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<button onClick={addTodo}>추가</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
</div>
);
};
export default App;
이제 테스트를 실행하면 통과합니다.
4. 코드 리팩터링 (Refactor 단계)
리팩터링 단계에서는 중복된 코드나 불필요한 로직을 제거합니다. 예를 들어, 입력값을 다루는 로직을 별도의 커스텀 훅으로 분리할 수 있습니다.
import React, { useState } from "react";
const useInput = (initialValue: string) => {
const [value, setValue] = useState(initialValue);
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value);
const reset = () => setValue("");
return { value, onChange, reset };
};
const App = () => {
const { value: input, onChange, reset } = useInput("");
const [todos, setTodos] = useState<string[]>([]);
const addTodo = () => {
setTodos([...todos, input]);
reset();
};
return (
<div>
<input
placeholder="할 일을 입력하세요"
value={input}
onChange={onChange}
/>
<button onClick={addTodo}>추가</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
</div>
);
};
export default App;
리팩터링 후에도 테스트는 여전히 통과해야 합니다.
TDD의 이점
React에서 TDD를 적용하면 다음과 같은 이점을 얻을 수 있습니다:
- 신뢰성 향상: 테스트가 코드의 동작을 보장하므로, 자신감을 가지고 리팩터링할 수 있습니다.
- 디자인 개선: TDD는 자연스럽게 단일 책임 원칙(SRP)을 따르도록 유도합니다.
- 문서화: 테스트 코드는 애플리케이션의 동작 방식을 명확히 보여줍니다.
- 버그 감소: 예상하지 못한 버그를 사전에 방지할 수 있습니다.
결론
React 애플리케이션에서 TDD를 적용하면 코드 품질과 유지 보수성을 높이고, 개발자가 실수를 방지할 수 있습니다. "할 일 목록" 예제는 단순한 사례지만, 이를 시작으로 더 복잡한 애플리케이션에도 TDD를 적용할 수 있습니다.
TDD를 실천하는 과정은 처음에는 익숙하지 않을 수 있지만, 반복을 통해 생산성과 코드 품질이 눈에 띄게 향상되는 것을 느낄 수 있을 것입니다. 오늘부터 React 프로젝트에 TDD를 도입해보세요!
'React' 카테고리의 다른 글
React에서 styled-components로 디자인 시스템 만들기 (0) | 2024.12.16 |
---|---|
React에서 디자인 시스템 구축하기 (0) | 2024.12.16 |
React에서 Cypress로 테스트 작성하기 (0) | 2024.12.16 |
React에서 Storybook으로 UI 컴포넌트 개발하기 (0) | 2024.12.16 |
React에서 Test Coverage 확인하기 (0) | 2024.12.16 |