kimyu0218
  • [spring] BDD 스타일로 테스트 코드 작성하기
    2025년 03월 09일 23시 45분 00초에 업로드 된 글입니다.
    작성자: @kimyu0218

    테스트 코드를 작성해본 사람이라면 given-when-then에 대해 들어봤을 것이다. 이는 테스트 코드를 작성하는 대표적인 스타일 중 하나다.

    • given : 초기 상태나 특정 입력이 주어진 상황(= 조건) 설정
    • when : 테스트 대상이 되는 행동
    • then : 예상되는 결과 검증
    given:	사용자가 로그인했다.
    when:	사용자가 상품을 장바구니에 추가한다.
    then: 	장바구니에 상품이 있어야 한다.

    given-when-then 패턴은 BDD에서 자주 사용되는데 지금부터 BDD에 대해 알아보자.

     

    BDD; Behavior-Driven Development

    BDD는 Behavior-driven development의 약자로, 소프트웨어의 동작을 중심으로 개발하는 방법론이다.

    • 시스템이 어떻게 동작해야 하는지 명확하게 정의하여 개발자 뿐만 아니라 기획자, 비즈니스 관계자까지도 어플리케이션 동작에 대해 같은 목표를 공유할 수 있다
    • 자연어 스타일의 시나리오(given-when-then)를 활용하여 모든 이해관계자가 이해할 수 있는 문서를 작성한다

     

    BDDAssertions & BDDMockito

    테스트 코드의 가독성을 높이기 위해 given-when-then을 주석으로 작성하곤 한다. 하지만 `BDDAssertions`와 `BDDMockito`를 활용하면 더 이상 주석을 작성하지 않아도 된다.

     

    assertJ는 테스트 단언문을 위한 라이브러리로 BDD 스타일의 `BDDAssertions` 메서드도 제공하고 있다.

    // BDD 적용 전
    assertThat(actual.getFirst().getMember()).isEqualTo(member);
    
    // BDD 적용 후
    then(actual.getFirst().getMember()).isEqualTo(member);

    `assertThat`과 `then`는 동일한 기능을 수행하지만, 후자가 BDD 스타일을 따르면서 자연스럽게 읽힌다.

    • (assertThat) `actual.getFirst().getMember()`가 `member`와 같은지 단언한다
    • (then) `actual.getFirst().getMember()`가 `member`와 같은지 기대한 결과를 확인한다

     

    모킹 라이브러리인 mockito도 BDD 스타일의 `BDDMockito`를 제공한다.

    // BDD 적용 전
    when(timeProvider.now()).willReturn(LocalDateTime.now());
    // (실제 when)
    verify(eventPublisher)
        .publishEvent(eq(new JoinMissionEvent(mission.getId(), DEVICE_TOKEN, NICKNAME_MEMBER_A)));
    
    // BDD 적용 후
    given(timeProvider.now()).willReturn(LocalDateTime.now());
    // (실제 when)
    then(eventPublisher)
        .should()
        .publishEvent(eq(new JoinMissionEvent(mission.getId(), DEVICE_TOKEN, NICKNAME_MEMBER_A)));

    마찬가지로 `when`과 `given`은 동일한 기능을 수행한다. 하지만 given-when-then 패턴과 달라 가독성이 떨어진다.

    • (when) `timeProvider.now()`를 실행하면 `LocalDateTime.now()`를 반환한다 (given-when-then 패턴의 when과 다름!)
    • (given) `timeProvider.now()`를 실행하면 `LocalDateTime.now()`를 반환한다
    • (verify) `eventPublisher`는 `publishEvent`를 호출했는지 검증한다
    • (then) `eventPublisher`는 `publishEvent`를 호출해야 한다

    이처럼 `BDDAssertions`와 `BDDMockito`를 사용하면 테스트 코드를 이해하기 쉬워지며 BDD 스타일을 유지할 수 있다.


    참고자료

    댓글