given-when-then pattern

bdd

tdd

given-when-then pattern

주로 단위 테스트에서 사용되는 패턴으로 테스트를 초기 상태 설정(given), 테스트 실행(when), 결과 검증(then)으로 구조화한다

bdd(behavior-driven development) 스타일과 밀접한 관련이 있다

@Test
void shouldReturnUserName() {
    
    // given (테스트 데이터 및 mock 설정)
    UserRepository mockRepository = mock(UserRepository.class);
    when(mockRepository.findById(1L)).thenReturn(new User(1L, "hansanhha"));
    UserService userService = new UserService(mockRepository);

    // when (테스트 실행)
    String username = userService.getUserName(1L);

    // then (검증)
    assertEquals("hansanhha", username);
}

bdd

bdd(behavior-driven development, 행동 주도 개발)는 소프트웨어 기능을 사용자의 행동 관점에서 기술하고 테스트하는 개발 방식이다

tdd에서 발전한 개념으로 기능의 동작(behavior)을 중심으로 테스트를 작성하며 단위 테스트(mockito) 뿐만 아니라 통합 테스트, e2e 테스트(cucumber)에도 적용할 수 있다

bdd 스타일의 테스트 코드 작성 시 참고할 점

// given...when...then 자연어 스타일로 메서드 이름을 지어 가독성을 높인다
@Test
void givenTwoNumbers_whenAdding_thenShouldReturnSum() {

    // bdd 스타일, given-when-then 패턴 사용
    // '두 개의 숫자가 주어졌을 때, 이를 더하면 합이 반환되어야 한다'라는 사용자 행동 중심의 테스트 코드 작성한다
    
    // given (초기 상태 설정)
    Calculator calculator = new Calculator();

    // when (테스트할 동작 수행)
    int result = calculator.add(2, 3);

    // then (결과 검증)
    assertEquals(5, result);
}

tdd

tdd(test-driven development, 테스트 주도 개발)는 테스트를 먼저 작성한 후, 이를 통과하는 최소한의 코드를 구현하는 개발 방식이다

테스트가 실패하는 것을 먼저 확인하고 점진적으로 기능을 구현해나가는 메커니즘을 갖는다

tdd 핵심 원칙

tdd는 red-green-refactor 라는 3단계를 반복한다

red (실패하는 테스트 작성)

green (코드 작성 및 테스트 통과)

refactor (코드 리팩토링)

이 과정을 반복하면서 점진적으로 코드를 개선함으로써 신뢰할 수 있는 테스트를 기반으로 개발하게 된다

tdd 예시

1. Calculator에 add 메서드를 추가한다

실패하는 테스트를 작성한다 (red)

class CalculatorTest {
    
    // add 메서드가 구현되지 않았기 때문에 컴파일 에러가 발생한다
    @Test
    void shouldReturnSumOfTwoNumbers() {
        Calculator calculator = new Calcualtor();
        int result = calculator.add(1, 2);
        assertEquals(5, result);
    }
}

2. add 메서드 구현

최소한의 코드를 작성한다 (green)

public class Calculator {
    
    // 테스트가 통과되도록 add 메서드를 구현한다
    int add(int a, int b) {
        return a + b;
    }
}

3. 코드 리팩토링

구현한 코드를 개선한다 (refactor)

class Calculator {
    
    // 로깅 추가
    // 리팩토링을 하더라도 테스트가 여전히 통과되는지 확인해야 한다
    int add(int a, int b) {
        log.info("Adding: {} + {}", a, b);
        return a + b;
    }
}

tdd의 장단점

장점

단점

tdd와 bdd

tdd: 코드를 구현하기 전 테스트를 먼저 작성하는 개발 방법론

bdd: 사용자의 행동을 중심으로 테스트를 작성하는 스타일

tdd와 bdd는 상충되는 개념이 아니라 서로 보완적인 관계로 tdd 방식으로 개발하면서 bdd 스타일로 테스트 코드를 작성할 수 있다

red-green-refactor 프로세스를 따르면서 bdd 스타일의 given-when-then 패턴으로 코드의 가독성을 높이는 방식