← Posts

Testing · TDD · Refactoring

TDD - 실패하는 테스트부터 쓴다

테스트를 나중이 아니라 먼저 쓴다. 빨강-초록-리팩터 사이클, 왜 먼저 쓰면 요구가 고정되고 설계 압력이 생기는지, 그리고 TDD를 둘러싼 오해와 안 맞는 자리까지.

목차
  1. 테스트를 나중에 쓰면
  2. 빨강-초록-리팩터
  3. 왜 먼저 쓰나
  4. 최소로만 통과시킨다
  5. 리팩터는 초록일 때만
  6. TDD를 둘러싼 오해
  7. 실무에서: 늘 맞지는 않는다
  8. 정리

지금까지는 “코드를 짜고 테스트한다”였다. TDD는 순서를 뒤집는다 - 테스트를 먼저 쓴다. 반직관적이지만, 그 순서가 값을 낸다.

테스트를 나중에 쓰면

보통은 구현을 끝내고 테스트를 짠다. 그런데 이러면 문제가 생긴다.

  • 구현에 맞춰 짜게 된다 - 이미 돌아가는 코드를 보며 짜니, “통과할 걸 아는” 테스트만 나온다. 정작 놓친 경우는 테스트도 안 짠다.
  • 미루다 안 짠다 - “일단 돌아가니 나중에”가 쌓여, 바쁘면 결국 생략된다.

TDD는 이 순서를 뒤집어, 테스트가 구현을 끌고 가게 한다.

빨강-초록-리팩터

TDD는 아주 짧은 사이클을 반복한다.

diagramdiagram
  • 빨강(red) - 아직 없는 기능의 테스트를 먼저 쓴다. 당연히 실패한다(구현이 없으니까).
  • 초록(green) - 그 테스트를 통과시킬 최소한의 코드만 쓴다.
  • 리팩터(refactor) - 초록불을 지키며 구조를 다듬는다.

이 셋을 몇 분 단위로 돈다. 기능 하나를 작은 테스트 여러 개로 쪼개, 한 번에 하나씩 빨강 → 초록 → 리팩터.

왜 먼저 쓰나

순서를 뒤집으면 세 가지가 따라온다.

  • 요구가 먼저 고정된다 - “이 함수는 무엇을 해야 하나”를 테스트로 먼저 못 박으니, 만들 것이 명확해진다. 통과 = 정의된 완료.
  • 설계 압력이 생긴다 - 테스트를 먼저 쓰려면 그 코드가 테스트하기 쉬워야 한다. 자연히 의존성이 정리되고(왜 테스트하나에서 본 그 압력), 결합이 낮아진다.
  • 딱 필요한 만큼만 짠다 - 테스트가 요구하지 않는 코드는 안 쓰게 된다(과잉 구현 방지).

최소로만 통과시킨다

TDD에서 가장 반직관적인 대목이다. 초록 단계에선 정말 최소한만 짠다 - 심지어 “값을 그냥 반환”하는 가짜 구현으로라도 통과시킨다.

plaintext
테스트: add(2,3)은 5   →  구현: return 5   (일단 통과)
테스트: add(1,1)은 2   →  이제 return 5로는 안 됨 → return a+b

바보 같아 보이지만 목적이 있다. 테스트가 요구할 때만 코드가 는다. 한 번에 완성하려 들지 않고, 다음 테스트가 진짜 로직을 강제할 때 일반화한다. 이렇게 하면 구현이 테스트에 딱 맞게 자라, 검증 안 된 코드가 안 생긴다.

리팩터는 초록일 때만

사이클의 세 번째 단계가 TDD의 숨은 값이다. 테스트가 초록인 상태에서만 구조를 바꾼다.

초록불은 “동작은 지금 맞다”는 뜻이니, 그 아래에선 이름을 바꾸든 함수를 쪼개든 겁이 없다 - 깨지면 즉시 빨개지니까. 겁 없이 바꾼다던 그 안전망을, TDD는 매 사이클마다 쓴다. 그래서 코드가 “돌아가지만 지저분한” 상태로 굳지 않고, 계속 다듬어진다.

TDD를 둘러싼 오해

  • “테스트를 많이 짜는 것”이 아니다 - TDD는 설계 방법이다. 테스트는 그 과정에서 나오는 부산물에 가깝다. 목표는 좋은 테스트가 아니라 좋은 설계.
  • “느려진다”가 아니다 - 앞에서 시간을 쓰지만, 늦게 잡을수록 비싼 버그를 앞당겨 막아 전체로는 아낀다. 다만 짧은 눈으로 보면 느려 보인다.
  • “항상 옳다”가 아니다 - 다음이 그 이야기다.

실무에서: 늘 맞지는 않는다

TDD는 강력하지만 만능은 아니다.

  • 요구가 또렷할 때 잘 맞는다 - 규칙이 분명한 로직(계산·검증·상태 전이)은 테스트로 먼저 못 박기 쉽다.
  • 탐색적일 때는 덜 맞는다 - 무엇을 만들지 모른 채 실험하는 단계, UI 감각을 잡는 단계에선 테스트를 먼저 쓰기 어렵다. 이럴 땐 먼저 만져 보고 나중에 테스트를 붙이는 게 낫다.
  • 도그마가 아니라 도구다 - “무조건 TDD”보다, 요구가 또렷한 핵심 로직엔 쓰고 아닌 데선 유연하게.

정리

  • TDD는 테스트를 먼저 쓴다 - 빨강(실패 테스트) → 초록(최소 통과) → 리팩터(정리)를 짧게 반복.
  • 먼저 쓰면 요구가 고정되고, 설계 압력이 생기고, 딱 필요한 만큼만 짜게 된다.
  • 초록일 때만 리팩터링하니 매 사이클이 안전망 - 코드가 지저분한 채 굳지 않는다.
  • TDD는 설계 방법이지 “테스트 많이 짜기”가 아니고, 탐색적인 일엔 안 맞을 수 있다 - 도구로 쓴다.

다음 글은 시리즈를 닫으며, 이 테스트들을 믿을 수 있게 유지하는 실무로 간다.

관련 글