아래 코드에서 보면, ReviewService는
ReviewRepository, OrdersRepository, ProductRepository를 의존하고 있다.
@Service
@RequiredArgsConstructor
public class ReviewService {
private final ReviewRepository reviewRepository;
private final OrdersRepository ordersRepository;
private final ProductRepository productRepository;
@Transactional
public ResponseEntity<ReviewResponseDto> createReview(ReviewRequestDto requestDto, User user) {
Orders order = ordersRepository.findById(requestDto.getOrderId())
.orElseThrow(() -> new NullPointerException("해당하는 주문이 존재하지 않습니다"));
if (!order.getUser().equals(user)) {
throw new IllegalArgumentException("작성 권한이 없는 유저 입니다.");
}
Review review = reviewRepository.save(new Review(requestDto,order));
return ResponseEntity
.status(HttpStatus.CREATED.value())
.body(new ReviewResponseDto(reviewRepository.save(review)));
}
}
즉, springbootTest 에서 테스트를 하는 것이 아닌,
Service 클래스 하나를 단위 테스트를 하는 경우, ReviewService 클래스 인스턴스가 생성 되려면
코드에 선언된 3개의 레포지토리 클래스가 필요하다.
모듈 테스트의 목적은 어떤 입력이 올 때,
원하는 값이 return 되는지, 원하는 횟수만큼 내부 로직이 동작 되는지 확인을 하는 것이다.
즉, Service에 사용되는 내부 동작 Entity나 Dto를 디테일은 케이스에 맞춰서 일일하게 만들 필요가 없다.
@Mock
ReviewRepository reviewRepository;
@Mock
OrdersRepository ordersRepository;
@Mock
ProductRepository productRepository;
@Mock
Orders orders;
private String comment;
private Integer rating;
@BeforeEach
void setup() {
comment = "여기에 댓글 내용.";
rating = 3;
}
@Test
@DisplayName("[201] 성공 케이스")
void createReview() {
// 여기서 가짜 Mock class를 Inject 해준다.
ReviewService reviewService = new ReviewService(reviewRepository, ordersRepository, productRepository);
//given -> 답정너 값 넣기
ReviewRequestDto requestDto = new ReviewRequestDto(1L, comment, rating);
Review review = new Review(comment, rating); // 1
Optional<Orders> optionalOrders = Optional.of(orders); //2
User user = new User(); //3
// when -> 답정너 대답 넣기
when(reviewRepository.save(any(Review.class))).thenReturn(review); // 1
when(ordersRepository.findById(any(Long.class))).thenReturn(optionalOrders); // 2
when(orders.getUser()).thenReturn(user); // 3
//when(orders.getUser().equals(user)).thenReturn(true); // premitive type return은 when을 사용할 수 없다.
//then
ResponseEntity<ReviewResponseDto> result = reviewService.createReview(requestDto, user);
assertThat(result.getBody().getComment()).isEqualTo(review.getComment());
assertThat(result.getBody().getRating()).isEqualTo(review.getRating());
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.CREATED);
}
@Mock
ReviewRepository reviewRepository;
@Mock
OrdersRepository ordersRepository;
@Mock
ProductRepository productRepository;
//...(생략)
@Test
@DisplayName("[201] 성공 케이스")
void createReview() {
// 여기서 가짜 Mock class를 Inject 해준다.
ReviewService reviewService = new ReviewService(reviewRepository, ordersRepository, productRepository);
// ... 생략
}
<aside> 💡 given을 넣는 이유는 service 내부 동작 로직을 확인하기 위해서다.
</aside>
<aside> 💡 이런 given이 주어질 때, Service 함수는 이런 동작을 할거다~~ 가정을 하면서 given을 넣어줘야 한다.
</aside>
@Test
@DisplayName("[201] 성공 케이스")
void createReview(){
// ... 생략
//given -> 답정너 값 넣기
ReviewRequestDto requestDto = new ReviewRequestDto(1L, comment, rating);
Review review = new Review(comment, rating); // 1
Optional<Orders> optionalOrders = Optional.of(orders); //2
User user = new User(); //3
// 생략
}