BDD — 테스트를 대화로 만드는 방법

TDD를 몇 달 실천하고 나면 이상한 상황과 마주치게 된다. 테스트가 모두 통과한다. 코드도 깔끔하다. 그런데 출시된 기능이 사용자가 원하는 게 아니다. TDD는 “코드를 올바르게 만드는 것”에는 효과적이지만, “올바른 코드를 만드는 것”을 보장하지는 않는다. BDD는 이 간극을 메우기 위해 등장했다.

”테스트”라는 단어의 문제

TDD를 처음 팀에 도입하려 할 때 가장 흔한 반응은 두 가지다. 개발자는 “또 테스트 얘기야?”라고 한다. 기획자나 QA는 “그건 개발자 얘기네요”라고 한다. “테스트”라는 단어는 본질적으로 기술적인 냄새가 난다. 비즈니스 담당자가 참여할 여지가 없다.

2003년 XP 컨퍼런스에서 Dan North는 이 문제를 직면했다. 그는 JUnit 스타일의 TDD를 팀에 가르치면서 사람들이 “무엇을 테스트해야 하는가”, “테스트 이름을 어떻게 짓는가”라는 질문에서 막힌다는 걸 발견했다. 그의 해결책은 간단했다. 테스트 이름을 문장으로 써라.

// 전통적 TDD 스타일
@Test
void testWithdrawal() { ... }

// BDD 스타일
@Test
void accountHolderWithdrawsCashWhenAccountHasSufficientFunds() { ... }

이름을 문장으로 쓰는 순간, 테스트는 명세가 된다. 그리고 그 명세를 비개발자도 이해할 수 있다면, 협업의 문이 열린다.

TDD에서 BDD로: 피드백 루프의 확장

TDD의 피드백 루프는 기술적이다.

실패하는 테스트 작성 → 최소 구현 → 리팩토링
(초~분 단위 루프)

이 루프는 “구현이 명세와 일치하는가”를 검증한다. 하지만 “명세 자체가 올바른가”는 검증하지 못한다. BDD는 이 루프 바깥에 더 큰 루프를 추가한다.

비즈니스 시나리오 협의 → 인수 테스트(시나리오) 작성 → TDD로 구현
(일~주 단위 루프)

안쪽 루프(TDD)는 코드 품질을 보장하고, 바깥 루프(BDD)는 올바른 것을 만들고 있음을 보장한다. BDD는 TDD를 대체하지 않는다. TDD를 포함하면서 확장한다.

Three Amigos: 공통 언어의 탄생

BDD에서 가장 중요한 실천은 Three Amigos 미팅이다. 세 역할이 한자리에 모인다.

  • 개발자: “어떻게 구현할 것인가”를 생각한다
  • QA: “무엇이 잘못될 수 있는가”를 생각한다
  • 비즈니스(PO/기획자): “왜 이것이 필요한가”를 생각한다

이 세 관점이 만날 때 요구사항의 모호함이 드러난다. 기획서에 “사용자는 장바구니에 상품을 추가할 수 있다”라고 쓰여 있다면, Three Amigos 미팅에서 다음 질문들이 나온다.

  • 재고가 없는 상품은 추가할 수 있는가? (QA)
  • 이미 담긴 상품을 다시 추가하면 수량이 늘어나는가, 중복으로 추가되는가? (개발자)
  • 비회원도 장바구니를 사용할 수 있어야 하는가? (비즈니스)

이 대화의 결과물이 예시(Example) 다. 추상적 요구사항이 구체적 예시로 변환된다.

Example Mapping: 예시로 요구사항을 명세하기

Example Mapping은 Three Amigos 미팅을 구조화하는 기법이다. 네 가지 카드를 사용한다.

노란 카드 — User Story
  "사용자는 장바구니에 상품을 추가할 수 있다"

파란 카드 — Rule (비즈니스 규칙)
  "재고 있는 상품만 추가 가능"
  "최대 99개까지 담을 수 있다"
  "비회원은 세션 기반 장바구니 사용"

초록 카드 — Example (구체적 예시)
  "재고 5개인 상품을 3개 담으면 → 성공"
  "재고 0개인 상품을 담으면 → 실패, '재고 없음' 메시지"
  "이미 3개 담긴 상품을 1개 더 담으면 → 4개가 됨"

빨간 카드 — Question (미해결 질문)
  "재고 부족 시 알림 이메일을 보내는가?"

Example Mapping이 끝나면 빨간 카드(미해결 질문)가 없어야 개발을 시작할 수 있다. 빨간 카드가 있는 채로 개발하면 추측으로 구현하게 된다.

BDD가 막는 함정: 잘못된 것을 완벽하게 만들기

소프트웨어 개발에서 가장 비싼 실수는 잘못된 기능을 완벽하게 구현하는 것이다. 코드 품질이 높고 테스트 커버리지가 100%여도, 사용자가 원하지 않는 기능이라면 전부 쓸모없다.

BDD의 핵심 가치는 이 함정을 방지하는 것이다. 개발을 시작하기 전에 비즈니스, QA, 개발자가 동일한 예시를 보고 동의한다. 구현이 끝나면 그 예시가 자동화된 테스트로 통과한다. 예시가 통과하면 “우리가 협의한 것을 만들었다”는 증거가 된다.

Before BDD:
기획서 → 개발자 해석 → 구현 → QA 테스트 → "이게 아닌데요"

After BDD:
기획서 + Three Amigos → 구체적 예시 합의 → 구현 → 예시 통과 → 출시

BDD와 TDD의 관계 정리

BDD를 도입한다고 TDD를 버리는 게 아니다. 레벨이 다른 두 피드백 루프가 공존한다.

[BDD 레벨] Feature 파일 (Gherkin) → Cucumber/Behave → 인수 테스트 통과
                                              ↓
[TDD 레벨] 단위 테스트 → Red-Green-Refactor → 내부 설계 보장

BDD 시나리오가 인수 기준을 정의한다. 그 기준을 충족시키기 위해 내부를 TDD로 구현한다. BDD는 “무엇을 만들 것인가”를 명확히 하고, TDD는 “어떻게 올바르게 만들 것인가”를 보장한다.

실무에서 BDD를 처음 적용할 때의 조언이 있다. 도구(Cucumber, JBehave)부터 시작하지 말고 대화부터 시작하라. Three Amigos 미팅과 Example Mapping을 먼저 실천하는 것만으로도 요구사항의 품질이 눈에 띄게 올라간다. 도구는 그다음이다.