한 줄 요약: TDD(Test-Driven Development)란, 구현 코드 작성 전에 실패하는 테스트를 먼저 작성하고, 테스트를 통과하는 최소한의 코드를 구현한 뒤, 리팩토링하는 Red-Green-Refactor 사이클을 반복하는 개발 방법론이다.


1. TDD란 무엇인가?

건물 설계에서 청사진을 먼저 그리는 것처럼, TDD는 “코드가 어떻게 동작해야 하는지”를 테스트로 먼저 정의합니다. 코드를 짜기 전에 “이 함수는 2+2 입력 시 4를 반환해야 한다”는 명세(테스트)를 작성합니다.

Kent Beck이 1990년대 Extreme Programming(XP)의 핵심 실천 방법으로 정립했으며, 현재는 고품질 소프트웨어 개발의 표준 방법론입니다.

TDD의 핵심 효과:

  • 버그를 초기에 발견 (나중에 발견할수록 수정 비용 10배 증가)
  • 테스트가 살아있는 문서 역할
  • 리팩토링에 대한 자신감
  • AI 코딩 시대: AI가 생성한 코드의 검증 수단

2. 핵심 개념 이해하기

Red-Green-Refactor 사이클

RED: 실패하는 테스트 작성
  ↓
실패 확인 (빨간불 🔴)
  ↓
GREEN: 테스트를 통과하는 최소한의 코드 작성
  ↓
통과 확인 (초록불 🟢)
  ↓
REFACTOR: 코드 품질 개선 (테스트는 통과 유지)
  ↓
처음으로 반복 🔄

TDD vs 일반 개발 비교

단계 일반 개발 TDD
1단계 코드 작성 테스트 작성 (RED)
2단계 수동 테스트 최소 코드 구현 (GREEN)
3단계 (가끔) 테스트 작성 리팩토링 (REFACTOR)
4단계 버그 발견 후 수정 자동으로 버그 방지

AI 시대의 TDD

# AI에게 코드 생성을 요청할 때 TDD 활용:

# 1. 먼저 테스트를 작성해서 AI에게 전달
"""
다음 테스트를 모두 통과하는 calculate_discount() 함수를 작성해줘:

def test_regular_customer():
    assert calculate_discount(100, "regular") == 10  # 10% 할인

def test_premium_customer():
    assert calculate_discount(100, "premium") == 20  # 20% 할인

def test_invalid_type():
    with pytest.raises(ValueError):
        calculate_discount(100, "invalid")
"""

# 2. AI가 생성한 코드를 테스트로 자동 검증
# → 테스트 통과 = 코드 정확성 보장

3. 실무 적용 예시

Python pytest를 활용한 TDD 사이클 예시입니다.

# test_shopping_cart.py — 먼저 작성 (RED 단계)
import pytest
from shopping_cart import ShoppingCart

class TestShoppingCart:
    def setup_method(self):
        self.cart = ShoppingCart()

    def test_add_item(self):
        self.cart.add_item("사과", 1000, 2)
        assert self.cart.total() == 2000

    def test_remove_item(self):
        self.cart.add_item("바나나", 500, 3)
        self.cart.remove_item("바나나")
        assert self.cart.total() == 0

    def test_discount_coupon(self):
        self.cart.add_item("오렌지", 2000, 1)
        self.cart.apply_coupon("SAVE10")  # 10% 할인
        assert self.cart.total() == 1800

    def test_empty_cart_total(self):
        assert self.cart.total() == 0

    def test_invalid_coupon(self):
        with pytest.raises(ValueError, match="유효하지 않은 쿠폰"):
            self.cart.apply_coupon("INVALID")
# shopping_cart.py — 이후에 작성 (GREEN 단계)
class ShoppingCart:
    VALID_COUPONS = {"SAVE10": 0.10, "SAVE20": 0.20}

    def __init__(self):
        self._items = {}
        self._discount = 0.0

    def add_item(self, name: str, price: int, quantity: int):
        self._items[name] = {"price": price, "quantity": quantity}

    def remove_item(self, name: str):
        self._items.pop(name, None)

    def apply_coupon(self, code: str):
        if code not in self.VALID_COUPONS:
            raise ValueError(f"유효하지 않은 쿠폰: {code}")
        self._discount = self.VALID_COUPONS[code]

    def total(self) -> int:
        subtotal = sum(
            item["price"] * item["quantity"]
            for item in self._items.values()
        )
        return int(subtotal * (1 - self._discount))
# 테스트 실행
pytest test_shopping_cart.py -v

# 출력:
# test_shopping_cart.py::TestShoppingCart::test_add_item PASSED
# test_shopping_cart.py::TestShoppingCart::test_remove_item PASSED
# test_shopping_cart.py::TestShoppingCart::test_discount_coupon PASSED
# test_shopping_cart.py::TestShoppingCart::test_empty_cart_total PASSED
# test_shopping_cart.py::TestShoppingCart::test_invalid_coupon PASSED
# 5 passed in 0.12s

4. TDD vs 유사 개념 비교

구분 TDD BDD 일반 테스팅
테스트 시점 코드 전 요구사항 정의 시 코드 후
작성자 개발자 개발자+기획자 QA 팀
테스트 스타일 단위 테스트 Given-When-Then 다양
속도 빠른 피드백 빠른 피드백 늦은 피드백
AI 협업 ✅ 검증 도구 ✅ 명세 도구 보통

5. 마치며

TDD는 단기적으로는 느린 것처럼 보이지만, 장기적으로는 버그 수정 비용 절감과 리팩토링 자신감으로 전체 개발 속도를 높입니다. 특히 AI가 코드를 생성하는 시대에는 TDD가 AI 출력물의 품질 게이트 역할을 합니다. 하네스 엔지니어링(Harness Engineering)품질 게이트(Quality Gate)를 함께 학습하면 AI 시대의 소프트웨어 품질 관리 체계를 완성할 수 있습니다.

참고 자료

함께 읽으면 좋은 용어

이 개념과 함께 알아두면 이해가 깊어지는 관련 용어들입니다.

댓글 남기기