본문 바로가기
우아한테크코스 4기/레벨1

[Java] Mockito를 사용하여 TDD 적용해보기

by 나는후니 2022. 2. 17.

최근 우아한 테크 코스 교육 입과 선물(?)로 배민 5000원 쿠폰을 받았습니다.

ㅋㅋㅋ 나이쓰~

감사하게도 쿠폰을 받았는데 가만히 있을 수 없죠. 이 쿠폰이 생성되는 과정을 Mockito를 사용하여 TDD 적용해보겠습니다.

물론 실제처럼 작성하려 하면 굉장히 복잡할테니 엄청난 축약 버전으로 코드를 작성해보고자 합니다.

 

본문을 시작하기 앞서 왜 Mocking을 하는 것일까요?

실제로 개발을 할 때는 다른 팀, 외부 관계사 등등 다양한 포인트로 요청을 보낼 것입니다.

그런데 테스트 코드를 작성할 때 각 실제 포인트로 요청을 보내야 할까요?

저는 아니라고 생각합니다. 갑작스런 전사휴가(?) 혹은 점검으로 응답을 받지 못하는 등 이유가 있겠죠 ㅋㅋ. (반박 댓글점 부탁드립니다 ㅋ)

 

그래서 대역을 사용하는 것이고 그 중에서도 Mockito는 모의 객체를 만들어 쉽게 stubbing 할 수 있는 라이브러리이기 때문에 널리 사용되고 있는 것이죠.

참고
Mockito를 사용하기 위해서는 외부 라이브러리를 dependency에 추가해야 합니다. gradle 기준 아래 내용을 추가해주세요.

testImplementation 'org.mockito:mockito-core:3.12.4'

 

먼저 코드 흐름부터 이야기해보면

  • 쿠폰 생성 요청을 보낸다.
  • 쿠폰 생성이 불가하면 에러가 발생한다.
  • 쿠폰 생성이 가능하면 쿠폰 번호를 반환한다.

핵심적으로 검증할 대상은 쿠폰 생성이 불가하면 에러가 발생한다. 입니다.

에러를 검증하는 지점으로 CouponCreatorValidator, UserChecker, CouponChecker 를 만들어 입력값 자체를 검증하고 구매자가 존재하는지, 구매하고자 하는 쿠폰이 존재하는지, 대상 전화번호가 존재하는지 확인하게 될 것입니다.

이번 포스팅에서는 UserChecker와 CouponChecker를 mocking 하여 TDD로 코드를 작성하는 과정을 게시해보겠습니다.

Step 1. Red -> Green


먼저 Test 클래스를 하나 생성해서 상상하는대로 클래스 명을 작성하고, 메서드를 실행시켜줍니다.

이 때 UserChecker는 mocking 해줍니다. 가짜 검증기를 만들어 테스트가 원하는대로 진행되는지 먼저 확인해봅니다. 당연히 테스트는 실패하겠죠.

이제 모든 빨간색을 제거하면 됩니다. 하지만 아직 예외를 터트리지 않기 때문에 테스트가 통과하지 않습니다.

빨간색을 모두 제거했지만 아직 테스트는 통과하지 않았습니다.

Step 2. 최소한의 통과


이제 뼈대를 만들었으니 테스트가 Green이 될 수 있도록 코드를 최소한으로 변경해봅시다.

CouponCreator

public void register(CouponCreatorRequest couponCreatorRequest) {
    throw new NoUserException();
}

먼저 가장 쉽게 테스트를 통과시켜봅니다.
이제 UserChecker 를 stubbing 해서 원하는 결과를 return 하고 테스트가 통과되게끔 변경해봅시다.

참고
Mock 객체를 stubbing할 때는 BDDMockito 클래스를 사용합니다. 링크 에 접근하여 BDDMockito의 다양한 사용법을 알면 모의객체 테스팅이 더 편리해집니다.

@Test
void 유저_존재하지_않음_실패() {
    CouponCreatorRequest couponCreatorRequest = new CouponCreatorRequest("No User", null, null);
    CouponCreator couponCreator = new CouponCreator(mockUserChecker);

    // stubbing, NoUser 일 때, false를 반환해주는 것으로 가정한다. 
    BDDMockito.given(mockUserChecker.isUserExist("NoUser")).willReturn(false);

    assertThatCode(() -> couponCreator.register(couponCreatorRequest))
            .isInstanceOf(NoUserException.class);
}

그리고 register 메서드의 코드도 변경해봅니다.

public void register(CouponCreatorRequest couponCreatorRequest) {

    // user 정보를 담당하는 팀에게 응답 받는 부분이라고 생각하면 좋습니다.
    if (!userChecker.isUserExist(couponCreatorRequest.getUserId())) {
        throw new NoUserException();
    }
}

이제 테스트 코드를 실행시켜 보면 코드의 범용성도 높이고 Green으로 잘 변한 것도 확인할 수 있습니다.

이제 이 과정대로 똑같이 쿠폰이 존재하는지, 입력된 전화번호가 유저로 존재하는지 TDD로 작성할 수 있습니다.

차근차근 늘려나갑니다.

테스트 코드를 작성해나가면서, 반복적인 코드의 사용은 필드로 빼내서 테스트 코드를 깔끔하게 유지하는 것도 중요합니다.

Step 3. 리팩토링


이제 프로덕션 코드에 가서 코드를 깔끔하게 정리해주면 원하는대로 TDD가 완료됩니다.

간단하게 만들고자 코드를 최소화 했지만 이런 흐름으로 진행하면 됩니다!

 

정리

정말 초 간단 버전의 대역 테스트, TDD를 작성해보았습니다!  대역을 왜 사용하는지, 과연 Mockito를 사용하는 게 좋을 것인지, 직접 대역을 만들어 테스트 성능을 개선해볼 것인지 잘 고민하고 방법을 선택하면 좋을 것 같습니다.