지난 단위 테스트 개념에 이어서 Mockito를 연습해보자
productService에 있는 update 코드를 테스트해보자
@Transactional
public ProductResponseDto updateProduct(Long id, ProductMypriceRequestDto requestDto) {
int myprice = requestDto.getMyprice();
if (myprice < MIN_MY_PRICE) {
throw new IllegalArgumentException("유효하지 않은 관심 가격입니다. 최소 " + MIN_MY_PRICE + "원 이상으로 설정해 주세요.");
}
Product product = productRepository.findById(id)
.orElseThrow(() -> new NullPointerException("해당 상품을 찾을 수 없습니다."));
product.update(requestDto);
return new ProductResponseDto(product);
}여기서 들 수 있는 의문
테스트 코드에 생성자 주입을 넣을 수 있나? repository에 있는 findById는 어떻게 동작하지?
라는 의문이 들 수 있다
하지만 우리가 테스트 하고 싶은건 findById가 아니라 서비스에 있는 update 코드 자체가 잘 처리되는지이다
repository가 아니라 service만 테스트 하기 위해 Mock Object를 사용할 수 있다
그리고 그 Mock Object를 제공해주는 라이브러리가 Mockito 이다
Mockito
@ExtendWith(MockitoExtension.class) // @Mock 사용을 위해 설정합니다.
class ProductServiceTest {
@Mock
ProductRepository productRepository;
@Mock
FolderRepository folderRepository;
@Mock
ProductFolderRepository productFolderRepository;
...
Mockito를 사용하기 위해 따로 dependency를 추가할 필요는 없다
@ExtendWith(MockitoExtension.class) 애노테이션을 달아서 설정해주고 Mock 오브젝트로 사용할 가짜 객체(클래스나 인터페이스)를 @Mock 애노테이션을 달아주면 Mockito가 가짜객체를 만들어준다
@Test
@DisplayName("관심 상품 희망가 - 최저가 이상으로 변경")
void test1() {
// given
Long productId = 100L;
int myprice = ProductService.MIN_MY_PRICE + 3_000_000;
ProductMypriceRequestDto requestMyPriceDto = new ProductMypriceRequestDto();
requestMyPriceDto.setMyprice(myprice);
ProductService productService = new ProductService(productRepository, productFolderRepository, folderRepository);
// when
ProductResponseDto result = productService.updateProduct(productId, requestMyPriceDto);
// then
assertEquals(myprice, result.getMyprice());
}- given
- productId와 myprice를 임의로 넣어준다
- setMyprice를 이용해 requestMyPriceDto를 생성해준다
- 그리고 productService를 하나 만들어준다
- when
- 실제로 productService를 실행해 result값을 받는다
- then
- assertEquals를 이용해 내가 넣은 myprice와 결과물의 myprice가 같은지 비교해 Update가 잘 수행되고 있는지 확인한다
하지만 이대로 실행하면 오류가 발생한다
가짜 객체를 만들어 전달해주기만 하는게 아니라 사용 케이스를 제대로 정의해서 넘겨줘야하기 때문이다
다시 말하지만 우리는 update가 제대로 되는가? 가 중요한 포인트이다
사용 케이스를 추가한 코드를 다시 보자
@Test
@DisplayName("관심 상품 희망가 - 최저가 이상으로 변경")
void test1() {
// given
Long productId = 100L;
int myprice = ProductService.MIN_MY_PRICE + 3_000_000;
ProductMypriceRequestDto requestMyPriceDto = new ProductMypriceRequestDto();
requestMyPriceDto.setMyprice(myprice);
User user = new User();
ProductRequestDto requestProductDto = new ProductRequestDto(
"Apple <b>맥북</b> <b>프로</b> 16형 2021년 <b>M1</b> Max 10코어 실버 (MK1H3KH/A) ",
"https://shopping-phinf.pstatic.net/main_2941337/29413376619.20220705152340.jpg",
"https://search.shopping.naver.com/gate.nhn?id=29413376619",
3515000
);
Product product = new Product(requestProductDto, user);
ProductService productService = new ProductService(productRepository,folderRepository, productFolderRepository);
given(productRepository.findById(productId)).willReturn(Optional.of(product));
// when
ProductResponseDto result = productService.updateProduct(productId, requestMyPriceDto);
// then
assertEquals(myprice, result.getMyprice());
}product를 직접 만들어주는 부분이 추가되었다 (User, ProductRequestDto)
그리고 Mockito에 given이라는 method를 이용해 넣어줄 수 있다

(편-안)