(방법론) BDD와 TDD, 그리고 DDD(행동 주도 개발, 테스트 주도 개발, 도메인 주도 개발)

2022. 7. 21. 14:30개발 방법론

반응형

클린 아키텍처를 다시 읽으면서 BDD에 관한 언급이 아주 짤막하게 있었다.

테스트는 시스템의 일부인가? 아니면 별개인가? 어떤 종류의 테스트카 있는가? 단위 테스트와 통합 테스트는 서로 다른가?
인수 테스트, 기능 테스트, Cucumber 테스트, TDD 테스트, BDD 테스트, 컴포넌트 테스트 등은 어떻지? - 28장 테스트의 경계, 262p

 

그래서 나는 BDD가 무엇인지 찾아보게 되었고, 아주 놀라운 사실들을 발견할 수 있었다.

 

 

🧐BDD(Behavior driven development)


직역하자면 '행동 주도 개발'이다.

 

어떤 행동을 말하는 것일까?

 

 

이 행동은 비지니스 로직에 관한 행동 일 것이다.

(역으로 생각하면 BDD의 특징이 비즈니스 요구사항에 집중할 수 있는 것이니)

 

 

'할인된 상품의 목록을 조회하는 행위'에 대한 예시를 생각해보자.

 

그럼 BDD에서는 이를 아래와 같은 테스트 형식의 시나리오로 작성할 수 있다.

 

제목: 할인된 상품의 목록 조회할 수 있습니다.

사용자는 할인된 상품의 목록을 조회할 수 있습니다.
할인된 상품의 재고가 없다면 빈 목록을 얻습니다.

시나리오1:
    // given
    할인된 상품의 목록이 존재한다면 상품 목록을 제공합니다.

     // when
    할인된 상품의 목록에 할인된 상품 1, 할인된 상품 2, 할인된 상품 3이 존재한다고 가정할 때,

    //then
    할인된 상품의 목록을 조회한다면 상품 목록에 저장된 상품이 있어야 합니다.

시나리오2:
    //given
    할인된 상품의 재고가 없다면 상품 목록이 비어있어야 합니다.

    //when
    할인된 상품의 목록이 빈 목록이 존재할 때,

    //then
    할인된 상품의 목록을 조회한다면 상품 목록이 비어있어야 합니다.(빈 상품 목록을 반환해야 합니다.)

 

(이 밖에도 저 행동하나만으로 여러가지 시나리오를 작성할 수 있다.)

 

 

 

그럼 다시 BDD로 돌아가보자.

 

 

BDD는 본질적으로 TDD를 근간으로 파생된 개발 방법이다.

 

그렇기 때문에 메서드의 동작 여부를 테스트하는 TDD에서

 

동작과 행동이 실제로 잘 이루어지는지에 대한 테스트가 추가된 것이 BDD다.

 

 

그렇기 때문에 테스트 코드를 먼저 작성해야함을 잊지 말자.

 

 

그리고 코드를 보자.

 

@SpringBootTest
class ProductServiceTest {
    private ProductService productService;
    private final Long EXISTED_ID_1 = 1L;
    private final Long EXISTED_ID_2 = 2L;
    
    private final ProductRepository productRepository = mock(ProductRepository.class);
    
    @BeforeEach
    void setUp() {
        productService = new ProductService(productRepository);
        
        Product product1 = Product.builder()
                                 .id(EXISTED_ID_1)
                                 .name("air jordan")
                                 .sale(true)
                                 .build();
                                 
       Product product2 = Product.builder()
                                 .id(EXISTED_ID_2)
                                 .name("macbookAir13")
                                 .sale(true)
                                 .build();
        
        //given                     
      	given(productRepository.findUserBySaleIsTrue()).willReturn(List.of(product1, product2));
   }
   
   
   @Test
   void getSaleProducts() {
       // when
       List<Product> sale = productService.getSaleProducts();
       
       
       // then
       assertThat(sale.size()).isNotEmpty();
       
       assertThat(sale.get(0).getName()).isEqualTo("air jordan");
       
       verify(productRepository).findUserBySaleIsTrue();
   }
   
   @Test
   void getEmptySaleProducts() {
       // given
       given(productRepository.findUserBySaleIsTrue()).willReturn(List.of());
       
       //when
       List<Product> sale = productService.getSaleProducts();
       
       // then
       assertThat(sale.size()).isEmpty();
       
       verify(productRepository).findUserBySaleIsTrue();
   }
       
}

 

테스트 코드를 이처럼 작성할 수 있다. (좀 더 정제할 수 있지만, 일단 이렇게 작성하기로 하자.)

 

 

Spring boot에서는 given, when, then을 쉽게 구현할 수 있다.

 

 

given, when,  then을 활용해서 우리가 얻을 수 있는 것은 무엇인가?

 

 

메서드에 대한 행위를 테스트 할 수 있다.

 

 

그리고 그 행위는 시나리오와 연관되며, 이 시나리오는 비지니스 요구사항과 직결된다.

 

 

그렇기 때문에 BDD의 특징이 바로 비지니스 요구사항의 개발에 집중할 수 있다는 것이다.

 

 

 

🧐DDD와는 어떤 관련이 있을까?


BDD의 장점은 '비지니스 로직'에 집중할 수 있다는 것이다.

 

 

어디서 많이 본 문구다.

 

DDD에서 봤을 것이다. DDD의 장점 중 하나로 꼽히는 것이 바로 '비지니스 로직에 집중할 수 있는 것'이니 말이다.

 

 

심지어 DDD의 핵심 중 하나인 '유비쿼터스 언어' 역시 BDD의 시나리오와 매우 흡사하다.

 

 

다만 DDD의 유비쿼터스언어는 개발자만을 위한 언어가 아니라는 차이점 정도가 있을 것이다.

 

 

 

DDD는 테스트를 먼저 작성해서 개발하는 방법이 아니다.

 

하지만 BDD는 테스트 주도 개발의 파생형이기에 테스트를 먼저 작성한다.

 

 

 

 

그럼 생각해보자. BDD와 DDD는 분리할 수 있는 것인가?

 

 

오히려 상호 보완관계에 있는 것이 아닌가?

 

 

DDD는 도메인 로직에 집중할 수 있게 해줌과 동시에 유비쿼터스 언어를 통해 소통에 장벽이 없도록 만들어 준다.

 

 

TDD 기반의 BDD는 도메인 로직에 집중하는 동시에, 도메인 로직을 테스트 검증하면서 구현한다.

 

 

 

그렇기에 둘을 동시에 사용하면 완벽한 조화를 이룰 수 있을 것으로 생각된다.

 

 

 

 

 

 

 

반응형