doistory

Unit Test에서 의존성 걱정 없이 테스트 작성 가능할까?: Mockito 와 BDDMockito 소개 본문

[ Devlopment ]/Spring

Unit Test에서 의존성 걱정 없이 테스트 작성 가능할까?: Mockito 와 BDDMockito 소개

떡볶이최고 2024. 10. 27. 16:52

mockito 에서 몰디브 한 잔 어떤데

1. Mockito

Mockito는 MIT 라이선스에 따라 출시된 Java용 오픈 소스 테스트 프레임워크

왜 써봐야 할까?
Spring은 DI(의존성 주입)을 통해 객체간 의존성을 관리 해준다.
그러나 이런 의존성은 테스트 시점에 문제를 발생시킨다. 특히 개발 단계에서 unit 테스트에 활용하기에 유용해보인다.

  • Mockito는 Mock 객체를 용이하게 사용할 수 있도록 지원하는 테스트 프레임워크이다.
  • 단위 테스트 시점에서 객체들의 의존관계 때문에 비즈니스로직에 대해 독립적으로 정확하게 작동하는 테스트 를 작성하기 어렵다.
  • 즉 해당 객체에 대한 기능만 테스트 하려는데, 의존성 가지는 다른 객체가 테스트에 영향을 미친다.
  • 이때 의존성을 가지는 객체들은 가짜(Mock)객체로 만들어 테스트 한다.

Mockito 간단 예제

Mock 객체에 원하는 동작을 미리 정하고 이를 기반으로 테스트 하게 된다.
아래는 간단한 사용 방법이다.

@ExtendWith(MockitoExtension.class)
class SmsServiceTest {

    // Mock객체 생성
    @Mock
    private SmsCertificationRepository smsCertificationRepository;

    // 의존성 주입
    @InjectMocks
    private SmsService smsService;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void 테스트 {
        // 테스트 작성
    }
}
  • @Mock 어노테이션을 사용해 Mock객체 생성
  • @InjectMocks를 이용해 해당 클래스로 의존성 주입

2. Mockito vs BDDMockito

mock 객체를 활용한 테스트를 위해 두 가지 방법이 있다. 우리는 프로젝트에 BDDMockito를 채택하기로 했다.
각 함수 단위 테스트가 아니라 서비스의 흐름대로 테스트가 가능하기 때문이다.
따라서 코드를 읽어봄으로써 비즈니스 로직을 이해하기 용이한 장점이 있다고 생각했다.

Mockito

  • mock 객체를 사용하여 when().thenReturn을 통해 테스트 코드를 작성한다.
  • import org.mockito.Mockito

BDDMockito

  • BDDMockito를 사용하면 given().willReturn()을 통해 테스트 코드를 작성한다.
  • import org.mockito.BDDMockito

3. BDDMockito

  • BDD는 Behavior-Driven Development (행위 주도 개발)을 말한다.
  • BDD 행위 주도 개발 :
    • 시나리오 기반으로 테스트. 즉 함수 단위 작성 X
    • 테스트 대상의 상태 변화를 테스트 한다.
    • 시나리오에 맞게 코드가 읽히도록 하는 목적. 비즈니스 요구사항에 집중하여 TestCase를 만드는 것.
    • 무엇을 테스트할 것인가에 초점
  • 권장 기본 패턴: Given, When, Then
    • 테스트 대상이 T상태에서 출발하여(Given) 어떤 상태 변화를 가했을 때(When) 기대하는 상태로 완료되어야 한다.(Then)
    • Side Effect가 전혀 없는 테스트 대상이라면 테스트 대상의 환경을 A 상태에 두고(Given) 어떤 행동을 요구했을 때(When) 기대하는 결과를 돌려받아야 한다. (Then)
  • BDDMockito 클래스는 stub을 할 때 사용할 메소드로 BDDMockito.given(Object)를 제공

간단 예제

import static org.mockito.BDDMockito.*;

@ExtendWith(MockitoExtension.class)
class SmsServiceTest {

    // Mock객체 생성
    @Mock
    private SmsCertificationRepository smsCertificationRepository;

    @Mock
    private SmsCertificationUtil smsUtil;

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private SmsService smsService;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

@Test
    void 문자전송_성공() {
        // Given (조건)
        given(items.hasItems()).willReturn(true);

        // When (기능 수행)
    boolean actual = person.hasItem();

        // Then (예상 결과)
    assertThat(actual).isTrue();
    }

 

후기

java, spring을 난생 처음 배우고 써보니 test는 전혀 생각하지 못했다. 수업 때도 테스트에 대해서 배우지 않았다.

SSAFY 프로젝트에서 메서드에 대해 단위 테스트를 하는 팀이 우리 팀 말고는 없다는 말을 들었다.

팀원 덕분에 테스트 코드를 작성해보며, 실제로 테스트가 왜 필요한지 알게 되었다.
테스트를 만들어보면서 여러가지 예외도 미리 생각을 하게 되었고, 오류 발생 가능한 지점도 미리 파악이 가능했다.

테스트를 통한 CI/CD를 도입하여 더욱 안정성 있는 프로그램을 작성할 수 있었다.

프론트 엔드 팀원들에게 오류 없는 API를 제공하여 칭찬을 받았다.

테스트 코드 작성은 어렵고 힘들었지만,,,,이렇게 팀 전체의 생산성을 높일 수 있었다.