TDD(Test-Driven Development) 학습
1️⃣ TDD란?
**테스트 주도 개발(Test-Driven Development, TDD)**은 기능을 구현하기 전에 테스트를 먼저 작성하고, 그 테스트를 통과시키는 방식으로 개발을 진행하는 방법론입니다.
- 단순히 테스트를 작성하는 것이 아니라, 개발과 테스트를 반복적 사이클로 수행하여 코드 품질을 높이는 것이 핵심입니다.
2️⃣ TDD의 기본 사이클
-
자동화된 테스트 시스템 준비
- 프로젝트에서 Jest, React Testing Library 등 자동화 테스트 환경을 세팅합니다.
- 테스트가 곧 개발의 기준이므로, 테스트 환경이 먼저 갖춰져야 합니다.
-
기능 사양 정의
- 개발할 기능에 대한 요구사항, 동작, 예외 사항 등을 정리합니다.
- 예: "사용자가 버튼을 클릭하면 카운트가 1 증가해야 한다."
-
테스트 명세 작성 및 실패 확인
- 작성한 테스트가 처음에는 실패함을 확인합니다.
- 이 과정에서 테스트가 기능의 동작을 정확히 검증하도록 설계합니다.
-
기능 구현
- 테스트를 통과시키기 위해 최대한 간단하고 빠르게 기능을 구현합니다.
- 구현의 목표는 테스트 통과이며, 완벽한 구조보다는 동작을 맞추는 것이 우선입니다.
-
테스트 통고 확인
- 작성한 테스트가 모두 성공하는지 확인합니다.
- 테스트가 통과하면 기능이 요구사항을 만족한다는 것을 검증한 것입니다.
-
리팩토링
- 구현한 기능이 테스트를 통과하면, 코드 구조, 중복 제거, 가독성 향상 등을 위해 리팩토링을 수행합니다.
- 리팩토링 후에도 테스트가 동과하는지 반드시 확인합니다.
-
반복
- 위 과정을 반복하면서 기능을 점진적으로 추가하고, 코드 품질을 유지합니다.
3️⃣ TDD의 장점
- 버그 예방: 기능 구현 전 테스트 작성 → 예외 처리 고려
- 설계 명확화: 테스트를 먼저 작성하면서 자연스럽게 기능 사양을 정의
- 리팩토링 안전성: 테스트가 있으므로 구조 개선 시 기능 보장
- 문서화 효과: 테스트 자체가 기능 설명서 역할
4️⃣ 간단한 예시 (React)
// Counter.test.tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Counter from "./Counter";
test("버튼 클릭 시 카운트가 1 증가한다", async () => {
render(<Conter />);
const button = screen.getByRole("button", { name: "증가" });
await userEvent.click();
expect(screen.getByText("Count: 1")).toBeInTheDocumet();
})
// Counter.tsx
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>증가</button>
</div>
);
}
- 테스트를 먼저 작성 → 실패 확인 → 기능 구현 → 테스트 통과 → 리팩토링 순으로 진행.