앞서 다형성을 이용해 테스트용 객체를 만들어 Service Layer 의존성을 갖는 Controller Layer를 테스트 하는 방법을 알아보았다.
다형성을 이용해 테스트 하는 방법은 테스트하는 경우에 따라 예상되는 반환값을 일일히 Bean 으로 설정해야하는 번거로움이 있다. 물론 테스트케이스마다 Bean 작성할 수 있다. 하지만 번거로운 일이 아닐 수 없다.
본 포스팅에서는 Mockito 프레임워크를 이용해 가짜객체(Mock) 를 만들어 테스트 하는 방법을 알아본다.
실습 예제
다형성을 이용해 익명 객체를 만들어 테스트 하기 에서 사용한 테스트 케이스에 Mockito 프레임워크를 적용한다.
MockitoExtension.class 추가
MockitoExtension은 JUnit4 MockitoJUnitRunner.class 에 해당하는 역할을 수행한다. Mock 을 초기화하고 엄격한 Stubbing 을 처리한다.
Mock 객체 설정
@Mock
- Mockito 에서 가장 널리 사용되는 주석 Mockito.mock() 을 직접 호출하지 않아도 Mock 객체를 생성하고 주입할 수 있다.
@InjectMocks
- @InjectMocks 는 객체를 만들고, @Mock 이나 @Spy 애너테이션으로 생성된 객체를 @InjectMocks 으로 생성한 객체에 주입한다.
MockMvcBuilders.standaloneSetup(Object ... controllers)
- @Controller 를 하나 이상 입력하고, 프로그래밍 방식으로 Spring MVC infrastructure를 구성하여 MockMvc 인스턴스를 빌드한다.
- MockMvcBuilder는 DispatcherServlet이 요구하는 "최소한"의 infrastructure를 만든다.
Mock 객체인 CatalogService를 주입받은 CatalogRestController를 MockMvcBuilder.standaloneSetup() 에 등록한다.
테스트 케이스 작성
13번째 줄에 작성된 내용은, catalogService.save(requestCatalog) 가 불릴 때, productId를 반환한다는 뜻이다.
Mock 객체인 catalogService의 save() 의 메소드를 호출 할 때, 사용자가 원하는 결과값을 직접 설정해야 한다. 다형성을 이용해 테스트 했을 때 익명클래스의 save() 메서드의 반환값을 작성하는 것과 동일하다.
여기까지 작성하고 테스트 케이스를 실행하면, 다음과 같은 메세지가 나오며 실패하는 것을 확인할 수 있다.
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'save' method:
catalogService.save(
RequestCatalog{productName='Seoul', stock=130, unitPrice=5000}
-> at com.example.userservice.catalogs.adapter.presentation.CatalogRestController.createCatalog(CatalogRestController.java:26)
- has following stubbing(s) with different arguments:
1. catalogService.save(
RequestCatalog{productName='Seoul', stock=130, unitPrice=5000}
-> at com.example.userservice.catalogs.adapter.presentation.CatalogRestControllerTest.create(CatalogRestControllerTest.java:58)
테스트 케이스에서 작성한 RequestCatalog 객체와, mockMvc.perform() 의 RequestBody 로 설정해 만들어진 RequestCatalog의 객체가 서로 달라 catalogService.save(requestCatalog) 가 실행되지 않은 것이다.
RequestCatalog 동일성/동등성 비교
productName='Seoul'
stock=130
unitPrice=5000
productName='Seoul'
stock=130
unitPrice=5000
테스트 코드에서 작성한 RequestCatalog 와 실제 코드에서 작성한 RequestCatalog의 Hashcode 값이 서로 다르기 때문에 테스트에 실패한 것이다.
객체를 비교할 땐 기본적으로 객체가 참조하는 값의 주소가 동일한지 확인(객체의 동일성)한다. 이것을 객체가 참조하는 값을 비교(객체의 동등성)하도록 변경해야 한다. Lombok 의 @EqualsAndHashCode 애너테이션을 붙이거나, Intellij IDEA 에서 제공하는 기능을 사용하면 손쉽게 equals()와 hashcode() 를 재정의 할 수 있다.
RequestCategory.java
Mockito Framework 를 이용해 테스트 케이스를 작성해 보았다. Mock 객체의 메서드에 특정 값 반환 뿐만 아니라, Exception 이 발생하도록 설정할 수 있다.
Mockito Framework를 이용하면, 다형성을 이용해 테스트 객체를 만드는 것보다 손쉽게 테스트 코드를 작성할 수 있다.