[SpringBoot] Mockito 이용하여 단위테스트 적용하는 방법, @Mock, @InjectMocks 어노테이션 이해하기

    Mock이란 어떤 행동을 했을 때 어떤 결과값을 줄 건지 정의한 가짜 객체를 뜻하며, Mockito는 Mock을 이용하여 테스트 코드를 작성할 수 있게 해주는 프레임워크이다.

     

    아래 AddressController 파일이 있고 그 안에는 addrSave() 함수로 주소를 저장하는 Service 함수가 실행된다.

    @RestController
    @RequiredArgsConstructor
    public class AddressController {
        private final AddressService addressService;
    
        @PostMapping("/v1/members/{id}/address")
        public AddressResponse addrSave(@PathVariable("id") Long memberId,
           @RequestBody CreateAddressRequest createAddressRequest) {
           return addressService.addrSave(memberId, createAddressRequest);
        }
    }

     

    Mockito 이용하여 단위테스트 적용 방법

    단위테스트를 적용해 실제로 addressService.addrSave() 함수가 실행되게 하지 않고 가짜 객체를 만들어서 addrSave() 함수를 실제로 실행 안 시키게 하였다.

    class AddressControllerUnitTest {
        @DisplayName("회원 배송지 저장 단위 테스트")
        @Test
        void testAddrSave() {
           //given
           AddressService addressService = Mockito.mock(AddressService.class);
           AddressResponse addressResponse = Mockito.mock(AddressResponse.class);
           AddressController addressController = new AddressController(addressService);
    
           //Mockito.when() -> given(), Mockito.thenReturn() -> willReturn()
           BDDMockito.given(addressService.addrSave(Mockito.anyLong(), Mockito.any(CreateAddressRequest.class)))
              .willReturn(addressResponse);
    
           //when
           addressResponse = addressController.addrSave(212L, new CreateAddressRequest());
    
           //then
           Mockito.verify(addressService, Mockito.times(1))
              .addrSave(Mockito.anyLong(), Mockito.any(CreateAddressRequest.class));
        }
    }

     

    위 코드에서 Mockito.mock(AddressService.class)로 AddressService 클래스를 가짜 객체로 만들었다. 그리고 그걸 AddressController 클래스에 주입하였다. 

     

    BDDMockito.given() 함수로 addressService.addrSave() 함수를 실행시키면 willReturn() 함수로 addressResponse 객체가 나오도록 지정하였다.

     

    BDDMockito는 Mockito 클래스를 상속받아서 이름만 바꿔놓은 것인데 given, when, then을 적용한 BDD 스타일로 바꿔 놓은 것이다.

    Mockito에서 when()은 given(), thenReturn()은 willReturn()이다.

    위 코드에서 addressService.addrSave(Long타입, CreateAddressRequest 객체)함수를 실행시키면 addressResponse 객체를 리턴하겠다는 실행을 정의한 것이다.  이것이 mock객체에 대한 행위를 지정한 것이며 이걸 stub 또는 stubbing이라고 한다.

     

    Mockito.verify()로 addrSave() 함수가 한번 실행이 되었는지 검증을 하였다.

     

    @Mock, @InjectMocks 어노테이션 이해하기

    이제 저걸 어노테이션 형태로 바꿔 보겠다. 우선 @Mock, @InjectMocks를 사용하려면 @ExtendWith(MockitoExtension.class)를 붙여야 한다.

    Mockito.mock()으로 만들었던 가짜 객체를 @Mock으로 만들었고, 가짜객체를 주입받았던 AddressController를 @InjectMocks로 만들었다. @InjectMock은 가짜로 만든 객체를 주입하겠다는 뜻이다.

    @ExtendWith(MockitoExtension.class)
    class AddressControllerUnitTest {
        @Mock
        AddressService addressService;
        @Mock
        AddressResponse addressResponse;
        @InjectMocks
        AddressController addressController;
    
        @DisplayName("회원 배송지 저장 단위 테스트")
        @Test
        void testAddrSave() {
           //given
           BDDMockito.given(addressService.addrSave(Mockito.anyLong(), Mockito.any(CreateAddressRequest.class)))
              .willReturn(addressResponse);
    
           //when
           addressResponse = addressController.addrSave(212L, new CreateAddressRequest());
    
           //then
           Mockito.verify(addressService, Mockito.times(1))
              .addrSave(Mockito.anyLong(), Mockito.any(CreateAddressRequest.class));
        }
    }

     

    댓글

    Designed by JB FACTORY