Spring Framework.

Mockito vs BDDMockito

PI.314 2022. 2. 4. 18:19

Mockito 와 BDDMockito를 비교하기 전에 간단하게 Mockito 개념에 대해 알아보자.

 

단위 테스트를 작성할 때 해당 객체에 대한 기능만 테스트 하고 싶은데 의존성을 갖는 다른 객체에 의해 테스트 결과가 영향을 받을 수 있다.

이렇게 의존을 가지는 객체를 우리가 원하는 동작만 하도록 만든 것이 Mock 객체다.

 

그리고 이런 Mock 객체를 직접 만들고 관리하기가 쉽지 않은데, Mockito는 이를 편리하게 사용하도록 지원해주는 대표적인 테스트 프레임워크다.

 

그러면 Mockito 이용하여 간단하게 작성한 테스트코드 예제를 살펴보자.

    @Test
    @DisplayName("주문정보 생성 성공")
    void createOrderUsingMockito() {
        // given
        when(orderRepository.save(any())).thenReturn(orderEntity);

        // when
        final OrderDto result = orderService.createOrder(orderDto);

        // then
        verify(orderRepository, times(1)).save(any());
        assertThat(result.getOrderId()).isNotEmpty();
        assertThat(result.getTotalPrice()).isEqualTo(result.getUnitPrice() * result.getQty());
    }

무언가 어색한 부분을 발견할 수 있을 것이다. 

Mockito는 스터빙을 when으로 하기 때문에 BDD style에 적합하지 않았고, 가독성이 많이 떨어져 코드를 작성할 때 약간 혼란스러웠다.

 

BDD 참고

더보기
더보기

BDD는 시나리오를 기반으로 테스트 케이스를 작성하며 함수 단위 테스트를 권장하지 않는다. 이 시나리오는 개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 레벨을 권장한다. 하나의 시나리오는 Given, When, Then 구조를 가지는 것을 기본 패턴으로 권장하며 각 절의 의미는 다음과 같다.

Feature : 테스트에 대상의 기능/책임을 명시한다.
Scenario : 테스트 목적에 대한 상황을 설명한다.
Given : 시나리오 진행에 필요한 값을 설정한다.
When : 시나리오를 진행하는데 필요한 조건을 명시한다.
Then : 시나리오를 완료했을 때 보장해야 하는 결과를 명시한다.

위의 내용을 개발 측면에서 더 간략하게 정리하면 테스트 대상의 상태 변화를 테스트하는 것이다.

테스트 대상은 A 상태에서 출발하며(Given) 어떤 상태 변화를 가했을 때(When) 기대하는 상태로 완료되어야 한다. (Then)

또는, Side Effect가 전혀 없는 테스트 대상이라면 테스트 대상의 환경을 A 상태에 두고(Given) 어떤 행동을 요구했을 때(When) 기대하는 결과를 돌려받아야 한다. (Then)

그러면 BDD style에 맞는 테스트 코드를 작성할 수 있는 테스트 프레임워크는 없을까?

 

이러한 불편한 점을 해결하기 위해서, Mockito를 상속하여 만든 BDDMockito 가 있다.

BDDMockito 클래스

BDDMockito는 BDD를 사용하여 테스트코드를 작성할 때, 시나리오에 맞게 테스트 코드가 읽힐 수 있도록 도와줄 수 있게 스터빙 함수의 이름을 변경했다. 아래 BDDMockito를 이용하여 작성한 코드를 살펴보자.

    @Test
    @DisplayName("주문정보 생성 성공")
    void createOrderUsingBDDMockito() {
        // given
        given(orderRepository.save(any())).willReturn(orderEntity);

        // when
        final OrderDto result = orderService.createOrder(orderDto);

        // then
        verify(orderRepository).save(any());
        assertThat(result.getOrderId()).isNotEmpty();
        assertThat(result.getTotalPrice()).isEqualTo(result.getUnitPrice() * result.getQty());
    }

가독성이 한결 좋아진 것을 비교해 볼 수 있다. 기능적으로는 Mockito와 거의 동일하므로 기존의 일반적인 테스트에서 BDD 패턴을 사용하려고 한다면, BDDMockito를 사용하여 테스트 전반적인 가독성을 높일 수 있다.