레스토랑 예약 사이트 만들기 6 - 리뷰 기능

새로운 리뷰 생성 오청을 처리하기 위한 control

@RestController
@RequiredArgsConstructor
public class ReviewController {

private final ReviewService reivewService;

@PostMapping("/restaurants/{restaurantId}/reviews")
public ResponseEntity<?> create(
@PathVariable Long restaurantId,
@Valid @RequestBody Review resource
) throws URISyntaxException {
Review review = reivewService.addReview(restaurantId, resource);

String url = "/restaurants/" + restaurantId + "/reviews/" + review.getId();
return ResponseEntity.created(new URI (url)).body("{}");
}
}
@WebMvcTest(ReviewController.class)
class ReviewControllerTest {

@Autowired
private MockMvc mockMvc;

@MockBean
private ReviewService reviewService;

@Test
public void 리뷰를_생성한다() throws Exception {
given(reviewService.addReview(eq(1L), any())).willReturn(
Review.builder()
.id(1004L)
.name("JOKER")
.score(3)
.description("Mat-it-da")
.build());


mockMvc.perform(post("/restaurants/1/reviews")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\":\"JOKER\", \"score\":3,\"description\" : \"Mat-it-da\"}"))
.andExpect(status().isCreated())
.andExpect(header().string("location", "/restaurants/1/reviews/1004"));

verify(reviewService).addReview(eq(1L), any());
}
}

Review 도메인 객체를 생성

@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class Review {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull
private Long restaurantId;

@NotEmpty
private String name;

@NotNull
private Integer score;

@NotEmpty
private String description;


}

Review를 저장하기 위한 Repository 생성

@Repository
public interface ReviewRepository extends JpaRepository<Review, Long> {
List<Review> findAllByRestaurantId(Long restaurantId);
}

Review Service 클래스를 생성한다.

@Service
@RequiredArgsConstructor
public class ReviewService {
private final ReviewRepository reviewRepository;

public Review addReview(Long restaurantId, Review review) {
review.setRestaurantId(restaurantId);
reviewRepository.save(review);
return review;
}
}

서비스 클래스를 테스트하기 위한 테스트 코드 작성

class ReviewServiceTest {

@Mock
private ReviewRepository reviewRepository;

private ReviewService reviewService;

@BeforeEach
public void setUp(){
MockitoAnnotations.initMocks(this);

reviewService = new ReviewService(reviewRepository);
}

@Test
public void 리뷰를_추가한다(){
Review review = Review.builder()
.name("JOKER")
.score(3)
.description("Mat-it-da")
.build();

reviewService.addReview(1004L, review);

verify(reviewRepository).save(any());
}
}

올바르지 않는 리뷰 요청에 대한 예외처리를 위한 테스트 코드 작성

@Test
public void 올바르지_않는_리뷰생성_요청() throws Exception {
mockMvc.perform(post("/restaurants/1/reviews")
.contentType(MediaType.APPLICATION_JSON)
.content("{}"))
.andExpect(status().isBadRequest());

verify(reviewService, never()).addReview(1004L, any());
}

Restaurant 서비스 클래스내에 review 컨텐츠

public Restaurant getRestaurant(Long id) {
Optional<Restaurant> optional = restaurantRepository.findById(id);

if (optional.isPresent()) {
Restaurant restaurant = optional.get();

// 해당 restaurant id값을 갖는 모든 Menu들을 가져온다.
List<MenuItem> menuItems = menuItemRepository.findAllByRestaurantId(id);
restaurant.setMenuItems(menuItems);

// 해당 restaurant id값을 갖는 모든 review들을 가져온다.
List<Review> reviews = reviewRepository.findAllByRestaurantId(id);
restaurant.setReviews(reviews);
return restaurant;
}else{
throw new RestaurantNotFoundException(id);
}
}

테스트 코드 작성

@Test
public void 특정_레스토랑을_가져온다() {
Restaurant restaurant = restaurantService.getRestaurant(1004L);

// 레스토랑 정보를 가져오는지 확인한다.
verify(restaurantRepository).findById(eq(1004L));
// 메뉴정보도 가져오는지 확인한다.
verify(menuItemRepository).findAllByRestaurantId(eq(1004L));
// 리뷰정보도 가져오는지 확인한다.
verify(reviewRepository).findAllByRestaurantId(eq(1004L));

// 가져온 정보들을 확인한다.
// 레스토랑 정보를 확인한다.
assertThat(restaurant.getId()).isEqualTo(1004L);
// 메뉴정보들을 확인한다.
MenuItem menuItem = restaurant.getMenuItems().get(0);
assertThat(menuItem.getName()).isEqualTo("Kimchi");
// 리뷰정보들을 확인한다.
Review review = restaurant.getReviews().get(0);
assertThat(review.getDescription()).isEqualTo("Bad");
}

레스토랑 요청에서 Review정보가 조회되는지 확인하는 테스트 코드 작성

@Test
public void 특정_가게_상세정보를_가져온다() throws Exception {
Restaurant restaurant = Restaurant.builder()
.id(1004L)
.name("JOKER House")
.address("Seoul")
.build();
// 메뉴 정보를 생성
MenuItem menuItem = MenuItem.builder()
.name("Kimchi")
.build();
// 리뷰 정보를 생성
Review review = Review.builder()
.name("JOKER")
.score(5)
.description("Great!")
.build();
// 레스토랑 객체에 메뉴 정보들을 저장한다.
restaurant.setMenuItems(Arrays.asList(menuItem));
// 레스토랑 객체에 리뷰 정보들을 저장한다.
restaurant.setReviews(Arrays.asList(review));


given(restaurantService.getRestaurant(1004L)).willReturn(restaurant);

ResultActions resultActions = mockMvc.perform(get("/restaurants/1004"));

resultActions
.andExpect(status().isOk())
// 레스토랑 정보가 들어있는지 확인한다.
.andExpect(content().string(containsString("\"id\":1004")))
.andExpect(content().string(containsString("\"name\":\"JOKER House\"")))
// 메뉴 정보가 들어있는지 확인한다.
.andExpect(content().string(containsString("Kimchi")))
// 리뷰 정보가 들어있는지 확인한다.
.andExpect(content().string(containsString("Great!")))
.andDo(print());

}
Share