From 1e526b43b85b1fc84c2225b8d34aa4e450e15ad4 Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 5 Dec 2023 18:16:27 +0900 Subject: [PATCH 01/12] =?UTF-8?q?#92=20refactor:=20ReservationProductReque?= =?UTF-8?q?stDto=20'price'=20=ED=95=84=EB=93=9C=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=EC=84=B1=20=EB=A9=94=EC=84=B8=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/ReservationProductRequestDto.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/fc/shimpyo_be/domain/reservationproduct/dto/request/ReservationProductRequestDto.java b/src/main/java/com/fc/shimpyo_be/domain/reservationproduct/dto/request/ReservationProductRequestDto.java index dce3fe8a..60c44be4 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/reservationproduct/dto/request/ReservationProductRequestDto.java +++ b/src/main/java/com/fc/shimpyo_be/domain/reservationproduct/dto/request/ReservationProductRequestDto.java @@ -26,7 +26,7 @@ public record ReservationProductRequestDto( String checkOut, String visitorName, String visitorPhone, - @Min(value = 0, message = "객실 이용 금액은 음수일 수 없습니다.") + @Min(value = 0, message = "객실 이용 금액은 0원 이상부터 가능합니다.") Integer price ) { } From 527a11b41655631a2ab6157e13cef20d6f975f4b Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 5 Dec 2023 18:18:54 +0900 Subject: [PATCH 02/12] =?UTF-8?q?#92=20refactor:=20=EC=88=99=EC=86=8C=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20=ED=8F=AC=ED=95=A8=ED=95=9C=20?= =?UTF-8?q?=EA=B0=9D=EC=8B=A4=20=EC=A0=95=EB=B3=B4=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20Querydsl?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9=ED=95=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Querydsl의 Projections 기능을 사용해 RoomWithProductResponseDto로 바로 조회할 수 있도록 구현 --- .../response/RoomWithProductResponseDto.java | 15 ++++++ .../room/repository/RoomRepository.java | 3 +- .../room/repository/RoomRepositoryCustom.java | 10 ++++ .../room/repository/RoomRepositoryImpl.java | 48 +++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java create mode 100644 src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryCustom.java create mode 100644 src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java new file mode 100644 index 00000000..f42faa08 --- /dev/null +++ b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java @@ -0,0 +1,15 @@ +package com.fc.shimpyo_be.domain.room.dto.response; + +public record RoomWithProductResponseDto( + Long productId, + String productName, + String productThumbnail, + Long roomId, + String roomName, + Integer standard, + Integer capacity, + String checkIn, + String checkOut, + Integer price +) { +} diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepository.java b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepository.java index b0478fdd..d5cda724 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepository.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepository.java @@ -3,6 +3,7 @@ import com.fc.shimpyo_be.domain.room.entity.Room; import org.springframework.data.jpa.repository.JpaRepository; -public interface RoomRepository extends JpaRepository { +public interface RoomRepository + extends JpaRepository, RoomRepositoryCustom { } diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryCustom.java b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryCustom.java new file mode 100644 index 00000000..3b8afbc1 --- /dev/null +++ b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryCustom.java @@ -0,0 +1,10 @@ +package com.fc.shimpyo_be.domain.room.repository; + +import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; + +import java.util.List; + +public interface RoomRepositoryCustom { + + List findAllInRoomIdsResponseDto(List roomIds); +} diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java new file mode 100644 index 00000000..16e9effb --- /dev/null +++ b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java @@ -0,0 +1,48 @@ +package com.fc.shimpyo_be.domain.room.repository; + +import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.core.types.dsl.StringExpression; +import com.querydsl.core.types.dsl.TimePath; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.time.LocalTime; +import java.util.List; + +import static com.fc.shimpyo_be.domain.product.entity.QProduct.product; +import static com.fc.shimpyo_be.domain.room.entity.QRoom.room; + +@RequiredArgsConstructor +public class RoomRepositoryImpl implements RoomRepositoryCustom { + + private final JPAQueryFactory jpaQueryFactory; + + @Override + public List findAllInRoomIdsResponseDto(List roomIds) { + return jpaQueryFactory.select( + Projections.constructor( + RoomWithProductResponseDto.class, + product.id.as("productId"), + product.name.as("productName"), + product.thumbnail.as("productThumbnail"), + room.id.as("roomId"), + room.name.as("roomName"), + room.standard, + room.capacity, + convertTimeToString(room.checkIn).as("checkIn"), + convertTimeToString(room.checkOut).as("checkOut"), + room.price + ) + ) + .from(room) + .join(room.product, product) + .where(room.id.in(roomIds)) + .fetch(); + } + + private StringExpression convertTimeToString(TimePath time) { + return Expressions.stringTemplate("TO_CHAR({0}, 'HH24:MI')", time); + } +} From 07059884956fe0193e565dfc0861285cb395e3ba Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 5 Dec 2023 18:19:31 +0900 Subject: [PATCH 03/12] =?UTF-8?q?#92=20refactor:=20=EC=88=99=EC=86=8C=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20=ED=8F=AC=ED=95=A8=ED=95=9C=20?= =?UTF-8?q?=EA=B0=9D=EC=8B=A4=20=EC=A0=95=EB=B3=B4=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/room/service/RoomService.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/com/fc/shimpyo_be/domain/room/service/RoomService.java diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/service/RoomService.java b/src/main/java/com/fc/shimpyo_be/domain/room/service/RoomService.java new file mode 100644 index 00000000..b45dd8c5 --- /dev/null +++ b/src/main/java/com/fc/shimpyo_be/domain/room/service/RoomService.java @@ -0,0 +1,26 @@ +package com.fc.shimpyo_be.domain.room.service; + +import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; +import com.fc.shimpyo_be.domain.room.repository.RoomRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@RequiredArgsConstructor +@Service +public class RoomService { + + private final RoomRepository roomRepository; + + @Transactional(readOnly = true) + public List getRoomsWithProductInfo(List roomIds) { + log.debug("{} ::: {}", getClass().getSimpleName(), "getRoomsWithProductInfo"); + + return roomRepository.findAllInRoomIdsResponseDto(roomIds); + } + +} From f348e12dd7c18b59ff8a99d8869625d03a10ff74 Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 5 Dec 2023 18:19:52 +0900 Subject: [PATCH 04/12] =?UTF-8?q?#92=20refactor:=20=EC=88=99=EC=86=8C=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20=ED=8F=AC=ED=95=A8=ED=95=9C=20?= =?UTF-8?q?=EA=B0=9D=EC=8B=A4=20=EC=A0=95=EB=B3=B4=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../room/controller/RoomRestController.java | 42 +++++++++++++++++++ .../GetRoomListWithProductInfoRequestDto.java | 11 +++++ .../RoomListWithProductInfoResponseDto.java | 8 ++++ 3 files changed, 61 insertions(+) create mode 100644 src/main/java/com/fc/shimpyo_be/domain/room/controller/RoomRestController.java create mode 100644 src/main/java/com/fc/shimpyo_be/domain/room/dto/request/GetRoomListWithProductInfoRequestDto.java create mode 100644 src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomListWithProductInfoResponseDto.java diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/controller/RoomRestController.java b/src/main/java/com/fc/shimpyo_be/domain/room/controller/RoomRestController.java new file mode 100644 index 00000000..af9eebb3 --- /dev/null +++ b/src/main/java/com/fc/shimpyo_be/domain/room/controller/RoomRestController.java @@ -0,0 +1,42 @@ +package com.fc.shimpyo_be.domain.room.controller; + +import com.fc.shimpyo_be.domain.room.dto.request.GetRoomListWithProductInfoRequestDto; +import com.fc.shimpyo_be.domain.room.dto.response.RoomListWithProductInfoResponseDto; +import com.fc.shimpyo_be.domain.room.service.RoomService; +import com.fc.shimpyo_be.global.common.ResponseDto; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RequiredArgsConstructor +@RequestMapping("/api/rooms") +@RestController +public class RoomRestController { + + private final RoomService roomService; + + @GetMapping + public ResponseEntity> getRoomsWithProductInfo( + @Valid @RequestBody GetRoomListWithProductInfoRequestDto request + ) { + log.debug("GET /api/rooms, roomIds : {}", request.roomIds()); + return ResponseEntity + .status(HttpStatus.OK) + .body( + ResponseDto.res( + HttpStatus.OK, + new RoomListWithProductInfoResponseDto( + roomService.getRoomsWithProductInfo(request.roomIds()) + ), + "숙소 정보를 포함한 객실 정보 리스트가 정상적으로 조회되었습니다." + ) + ); + } +} diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/dto/request/GetRoomListWithProductInfoRequestDto.java b/src/main/java/com/fc/shimpyo_be/domain/room/dto/request/GetRoomListWithProductInfoRequestDto.java new file mode 100644 index 00000000..bbcb83c3 --- /dev/null +++ b/src/main/java/com/fc/shimpyo_be/domain/room/dto/request/GetRoomListWithProductInfoRequestDto.java @@ -0,0 +1,11 @@ +package com.fc.shimpyo_be.domain.room.dto.request; + +import jakarta.validation.constraints.Size; + +import java.util.List; + +public record GetRoomListWithProductInfoRequestDto( + @Size(min = 1, max = 3, message = "최소 1개, 최대 3개의 객실 식별자 정보가 필요합니다.") + List roomIds +) { +} diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomListWithProductInfoResponseDto.java b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomListWithProductInfoResponseDto.java new file mode 100644 index 00000000..11463903 --- /dev/null +++ b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomListWithProductInfoResponseDto.java @@ -0,0 +1,8 @@ +package com.fc.shimpyo_be.domain.room.dto.response; + +import java.util.List; + +public record RoomListWithProductInfoResponseDto( + List rooms +) { +} From d616db98ce9b398811543836ce3f004bfa69c124 Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 5 Dec 2023 18:20:21 +0900 Subject: [PATCH 05/12] =?UTF-8?q?#92=20test:=20=EC=88=99=EC=86=8C=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20=ED=8F=AC=ED=95=A8=ED=95=9C=20?= =?UTF-8?q?=EA=B0=9D=EC=8B=A4=20=EC=A0=95=EB=B3=B4=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20Unit=20Te?= =?UTF-8?q?st=20=EC=9E=91=EC=84=B1=20=EB=B0=8F=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/RoomRestControllerTest.java | 108 ++++++++++++++++++ .../unit/repository/RoomRepositoryTest.java | 91 +++++++++++++++ .../room/unit/service/RoomServiceTest.java | 55 +++++++++ 3 files changed, 254 insertions(+) create mode 100644 src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java create mode 100644 src/test/java/com/fc/shimpyo_be/domain/room/unit/repository/RoomRepositoryTest.java create mode 100644 src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java new file mode 100644 index 00000000..99a2d1b5 --- /dev/null +++ b/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java @@ -0,0 +1,108 @@ +package com.fc.shimpyo_be.domain.room.unit.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fc.shimpyo_be.config.AbstractContainersSupport; +import com.fc.shimpyo_be.domain.room.dto.request.GetRoomListWithProductInfoRequestDto; +import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; +import com.fc.shimpyo_be.domain.room.service.RoomService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static org.hamcrest.Matchers.*; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +public class RoomRestControllerTest extends AbstractContainersSupport { + + private MockMvc mockMvc; + + @MockBean + private RoomService roomService; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @BeforeEach + void setUp(@Autowired WebApplicationContext applicationContext) { + this.mockMvc = MockMvcBuilders + .webAppContextSetup(applicationContext) + .apply(springSecurity()) + .alwaysDo(print()) + .build(); + } + + @WithMockUser(roles = "USER") + @DisplayName("[api][GET][정상] 숙소 정보 포함 객실 정보 리스트 조회 API 테스트") + @Test + void getRoomsWithProductInfo_api_test() throws Exception { + //given + String requestUrl = "/api/rooms"; + List roomIds = List.of(1L, 3L, 4L); + GetRoomListWithProductInfoRequestDto requestDto = new GetRoomListWithProductInfoRequestDto(roomIds); + + List rooms = List.of( + new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일", 1L, + "객실1", 2, 4, "14:00", "12:00", 100000), + new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일", 3L, + "객실3", 2, 4, "14:00", "11:30", 120000), + new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일", 4L, + "객실4", 2, 4, "13:00", "11:00", 95000) + ); + + given(roomService.getRoomsWithProductInfo(roomIds)) + .willReturn(rooms); + + //when & then + mockMvc.perform( + get(requestUrl) + .content(objectMapper.writeValueAsString(requestDto)) + .contentType(MediaType.APPLICATION_JSON) + .characterEncoding(StandardCharsets.UTF_8) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code", is(200))) + .andExpect(jsonPath("$.data").isNotEmpty()); + + verify(roomService, times(1)).getRoomsWithProductInfo(roomIds); + } + + @WithMockUser(roles = "USER") + @DisplayName("[api][GET][실패] 숙소 정보 포함 객실 정보 리스트 조회 API 테스트 - 요청 데이터 검증 에러") + @Test + void getRoomsWithProductInfo_api_request_validation_fail_test() throws Exception { + //given + String requestUrl = "/api/rooms"; + List roomIds = List.of(1L, 3L, 4L, 5L); + GetRoomListWithProductInfoRequestDto requestDto = new GetRoomListWithProductInfoRequestDto(roomIds); + + //when & then + mockMvc.perform( + get(requestUrl) + .content(objectMapper.writeValueAsString(requestDto)) + .contentType(MediaType.APPLICATION_JSON) + .characterEncoding(StandardCharsets.UTF_8) + ) + .andExpect(status().is4xxClientError()) + .andExpect(jsonPath("$.code", is(400))); + + verify(roomService, times(0)).getRoomsWithProductInfo(roomIds); + } +} diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/unit/repository/RoomRepositoryTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/unit/repository/RoomRepositoryTest.java new file mode 100644 index 00000000..617092b0 --- /dev/null +++ b/src/test/java/com/fc/shimpyo_be/domain/room/unit/repository/RoomRepositoryTest.java @@ -0,0 +1,91 @@ +package com.fc.shimpyo_be.domain.room.unit.repository; + +import com.fc.shimpyo_be.config.TestQuerydslConfig; +import com.fc.shimpyo_be.domain.product.entity.Category; +import com.fc.shimpyo_be.domain.product.entity.Product; +import com.fc.shimpyo_be.domain.product.repository.ProductRepository; +import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; +import com.fc.shimpyo_be.domain.room.entity.Room; +import com.fc.shimpyo_be.domain.room.repository.RoomRepository; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.time.LocalTime; +import java.util.LinkedList; +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +@Slf4j +@Import(TestQuerydslConfig.class) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@DataJpaTest +public class RoomRepositoryTest { + + @Autowired + private RoomRepository roomRepository; + + @Autowired + private ProductRepository productRepository; + + private List roomIds; + + @BeforeEach + void setUp() { + Product product = productRepository.save( + Product.builder() + .name("호텔") + .description("호텔 설명") + .address("호텔 도로명 주소") + .category(Category.TOURIST_HOTEL) + .thumbnail("호텔 이미지 썸네일") + .starAvg(3.5f) + .build() + ); + + roomIds = new LinkedList<>(); + + for (int i = 1; i <= 5; i++) { + roomIds.add( + roomRepository.save( + Room.builder() + .name("호텔 객실 " + i) + .description("객실 설명") + .product(product) + .standard(2) + .capacity(4) + .checkIn(LocalTime.of(13, 0)) + .checkOut(LocalTime.of(12, 0)) + .price(Integer.parseInt(String.format("1%d0000", i))) + .build() + ).getId() + ); + } + } + + @DisplayName("findAllInRoomIdsResponseDto 테스트") + @Test + void findAllInRoomIdsResponseDto() { + //given + + //when + List result = roomRepository.findAllInRoomIdsResponseDto(roomIds); + + //then + assertThat(result).hasSize(5); + assertThat(result.get(0).checkIn()).isInstanceOf(String.class); + } + + @AfterEach + void tearDown() { + roomRepository.deleteAll(); + productRepository.deleteAll(); + } +} diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java new file mode 100644 index 00000000..18cb74a6 --- /dev/null +++ b/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java @@ -0,0 +1,55 @@ +package com.fc.shimpyo_be.domain.room.unit.service; + +import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; +import com.fc.shimpyo_be.domain.room.repository.RoomRepository; +import com.fc.shimpyo_be.domain.room.service.RoomService; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +public class RoomServiceTest { + + @InjectMocks + private RoomService roomService; + + @Mock + private RoomRepository roomRepository; + + @DisplayName("") + @Test + void getRoomsWithProductInfo_test() { + //given + List roomIds = List.of(1L, 3L, 4L); + + List rooms = List.of( + new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일", 1L, + "객실1", 2, 4, "14:00", "12:00", 100000), + new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일", 3L, + "객실3", 2, 4, "14:00", "11:30", 120000), + new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일", 4L, + "객실4", 2, 4, "13:00", "11:00", 95000) + ); + + given(roomRepository.findAllInRoomIdsResponseDto(roomIds)) + .willReturn(rooms); + + //when + List result = roomService.getRoomsWithProductInfo(roomIds); + + //then + assertThat(result).hasSize(3); + + verify(roomRepository, times(1)).findAllInRoomIdsResponseDto(roomIds); + } +} From 043b1036f6b79aee2c4884e0afca55e589c6cfea Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 5 Dec 2023 18:20:44 +0900 Subject: [PATCH 06/12] =?UTF-8?q?#92=20test:=20=EC=88=99=EC=86=8C=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20=ED=8F=AC=ED=95=A8=ED=95=9C=20?= =?UTF-8?q?=EA=B0=9D=EC=8B=A4=20=EC=A0=95=EB=B3=B4=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20API=20Res?= =?UTF-8?q?t=20Docs=EB=A5=BC=20=EC=9C=84=ED=95=9C=20Test=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../room/docs/RoomRestControllerDocsTest.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java new file mode 100644 index 00000000..2fdb3719 --- /dev/null +++ b/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java @@ -0,0 +1,89 @@ +package com.fc.shimpyo_be.domain.room.docs; + +import com.fc.shimpyo_be.config.RestDocsSupport; +import com.fc.shimpyo_be.domain.room.dto.request.GetRoomListWithProductInfoRequestDto; +import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; +import com.fc.shimpyo_be.domain.room.service.RoomService; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.restdocs.constraints.ConstraintDescriptions; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.security.test.context.support.WithMockUser; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.snippet.Attributes.key; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class RoomRestControllerDocsTest extends RestDocsSupport { + + @MockBean + private RoomService roomService; + + private final ConstraintDescriptions getRoomListWithProductInfoDescriptions + = new ConstraintDescriptions(GetRoomListWithProductInfoRequestDto.class); + + @WithMockUser(roles = "USER") + @DisplayName("getRoomsWithProductInfo()는 숙소 정보를 포함한 객실 정보 리스트를 조회할 수 있다.") + @Test + void getRoomsWithProductInfo() throws Exception { + //given + String requestUrl = "/api/rooms"; + List roomIds = List.of(1L, 3L, 4L); + GetRoomListWithProductInfoRequestDto requestDto = new GetRoomListWithProductInfoRequestDto(roomIds); + + List rooms = List.of( + new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일 이미지 url", 1L, + "객실1", 2, 4, "14:00", "12:00", 100000), + new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일 이미지 url", 3L, + "객실3", 3, 5, "14:00", "11:30", 120000), + new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일 이미지 url", 4L, + "객실4", 2, 4, "13:00", "11:00", 95000) + ); + + given(roomService.getRoomsWithProductInfo(roomIds)) + .willReturn(rooms); + + //when & then + mockMvc.perform( + get(requestUrl) + .content(objectMapper.writeValueAsString(requestDto)) + .contentType(MediaType.APPLICATION_JSON) + .characterEncoding(StandardCharsets.UTF_8) + ) + .andExpect(status().isOk()) + .andDo(restDoc.document( + requestFields( + fieldWithPath("roomIds").type(JsonFieldType.ARRAY).description("조회할 객실 식별자 리스트") + .attributes(key("constraints").value( + getRoomListWithProductInfoDescriptions.descriptionsForProperty("roomIds"))) + ), + responseFields(responseCommon()).and( + fieldWithPath("data").type(JsonFieldType.OBJECT).description("응답 데이터"), + fieldWithPath("data.rooms").type(JsonFieldType.ARRAY).description("조회한 객실 정보 리스트"), + fieldWithPath("data.rooms[].productId").type(JsonFieldType.NUMBER).description("숙소 식별자"), + fieldWithPath("data.rooms[].productName").type(JsonFieldType.STRING).description("숙소명"), + fieldWithPath("data.rooms[].productThumbnail").type(JsonFieldType.STRING).description("숙소 썸네일 이미지 URL"), + fieldWithPath("data.rooms[].roomId").type(JsonFieldType.NUMBER).description("객실 식별자"), + fieldWithPath("data.rooms[].roomName").type(JsonFieldType.STRING).description("객실명"), + fieldWithPath("data.rooms[].standard").type(JsonFieldType.NUMBER).description("기준 인원"), + fieldWithPath("data.rooms[].capacity").type(JsonFieldType.NUMBER).description("최대 인원"), + fieldWithPath("data.rooms[].checkIn").type(JsonFieldType.STRING).description("체크인 시간"), + fieldWithPath("data.rooms[].checkOut").type(JsonFieldType.STRING).description("체크아웃 시간"), + fieldWithPath("data.rooms[].price").type(JsonFieldType.NUMBER).description("객실 가격") + ) + ) + ); + + verify(roomService, times(1)).getRoomsWithProductInfo(roomIds); + } +} From 81b17d733cea5134a039ee69be9691506190995b Mon Sep 17 00:00:00 2001 From: jo0oy Date: Wed, 6 Dec 2023 23:31:49 +0900 Subject: [PATCH 07/12] =?UTF-8?q?#92=20refactor:=20=EA=B0=9D=EC=8B=A4=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=A0=95=EB=B3=B4=EC=97=90=20'=EC=88=99?= =?UTF-8?q?=EC=86=8C=20=EC=A3=BC=EC=86=8C'=20=EC=B6=94=EA=B0=80=EB=90=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/RoomWithProductResponseDto.java | 1 + .../domain/room/repository/RoomRepositoryImpl.java | 1 + .../room/docs/RoomRestControllerDocsTest.java | 13 +++++++------ .../unit/controller/RoomRestControllerTest.java | 12 ++++++------ .../domain/room/unit/service/RoomServiceTest.java | 12 ++++++------ 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java index f42faa08..cef3cd5a 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java @@ -4,6 +4,7 @@ public record RoomWithProductResponseDto( Long productId, String productName, String productThumbnail, + String productAddress, Long roomId, String roomName, Integer standard, diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java index 16e9effb..f7cb9067 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java @@ -27,6 +27,7 @@ public List findAllInRoomIdsResponseDto(List r product.id.as("productId"), product.name.as("productName"), product.thumbnail.as("productThumbnail"), + product.address.as("productAddress"), room.id.as("roomId"), room.name.as("roomName"), room.standard, diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java index 2fdb3719..6dfec851 100644 --- a/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java +++ b/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java @@ -42,12 +42,12 @@ void getRoomsWithProductInfo() throws Exception { GetRoomListWithProductInfoRequestDto requestDto = new GetRoomListWithProductInfoRequestDto(roomIds); List rooms = List.of( - new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일 이미지 url", 1L, - "객실1", 2, 4, "14:00", "12:00", 100000), - new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일 이미지 url", 3L, - "객실3", 3, 5, "14:00", "11:30", 120000), - new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일 이미지 url", 4L, - "객실4", 2, 4, "13:00", "11:00", 95000) + new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일 이미지 url", "호텔1 주소", + 1L, "객실1", 2, 4, "14:00", "12:00", 100000), + new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일 이미지 url", "호텔2 주소", + 3L, "객실3", 3, 5, "14:00", "11:30", 120000), + new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일 이미지 url", "호텔3 주소", + 4L, "객실4", 2, 4, "13:00", "11:00", 95000) ); given(roomService.getRoomsWithProductInfo(roomIds)) @@ -73,6 +73,7 @@ void getRoomsWithProductInfo() throws Exception { fieldWithPath("data.rooms[].productId").type(JsonFieldType.NUMBER).description("숙소 식별자"), fieldWithPath("data.rooms[].productName").type(JsonFieldType.STRING).description("숙소명"), fieldWithPath("data.rooms[].productThumbnail").type(JsonFieldType.STRING).description("숙소 썸네일 이미지 URL"), + fieldWithPath("data.rooms[].productAddress").type(JsonFieldType.STRING).description("숙소 주소"), fieldWithPath("data.rooms[].roomId").type(JsonFieldType.NUMBER).description("객실 식별자"), fieldWithPath("data.rooms[].roomName").type(JsonFieldType.STRING).description("객실명"), fieldWithPath("data.rooms[].standard").type(JsonFieldType.NUMBER).description("기준 인원"), diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java index 99a2d1b5..87b3800a 100644 --- a/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java +++ b/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java @@ -59,12 +59,12 @@ void getRoomsWithProductInfo_api_test() throws Exception { GetRoomListWithProductInfoRequestDto requestDto = new GetRoomListWithProductInfoRequestDto(roomIds); List rooms = List.of( - new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일", 1L, - "객실1", 2, 4, "14:00", "12:00", 100000), - new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일", 3L, - "객실3", 2, 4, "14:00", "11:30", 120000), - new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일", 4L, - "객실4", 2, 4, "13:00", "11:00", 95000) + new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일", "호텔1 주소", + 1L, "객실1", 2, 4, "14:00", "12:00", 100000), + new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일", "호텔2 주소", + 3L, "객실3", 2, 4, "14:00", "11:30", 120000), + new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일", "호텔3 주소", + 4L, "객실4", 2, 4, "13:00", "11:00", 95000) ); given(roomService.getRoomsWithProductInfo(roomIds)) diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java index 18cb74a6..d3278e94 100644 --- a/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java +++ b/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java @@ -33,12 +33,12 @@ void getRoomsWithProductInfo_test() { List roomIds = List.of(1L, 3L, 4L); List rooms = List.of( - new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일", 1L, - "객실1", 2, 4, "14:00", "12:00", 100000), - new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일", 3L, - "객실3", 2, 4, "14:00", "11:30", 120000), - new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일", 4L, - "객실4", 2, 4, "13:00", "11:00", 95000) + new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일", "호텔1 주소", + 1L, "객실1", 2, 4, "14:00", "12:00", 100000), + new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일", "호텔2 주소", + 3L, "객실3", 2, 4, "14:00", "11:30", 120000), + new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일", "호텔3 주소", + 4L, "객실4", 2, 4, "13:00", "11:00", 95000) ); given(roomRepository.findAllInRoomIdsResponseDto(roomIds)) From e3a167a839c7dda0051aed3240616ce94dea933c Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 12 Dec 2023 05:15:08 +0900 Subject: [PATCH 08/12] =?UTF-8?q?#92=20refactor:=20=EB=B0=94=EB=A1=9C=20DT?= =?UTF-8?q?O=EB=A1=9C=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8A=94=20findAllInRo?= =?UTF-8?q?omIdsResponseDto()=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0,=20findAllInIdsWithProductAndPrice()=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../room/repository/RoomRepositoryCustom.java | 4 +-- .../room/repository/RoomRepositoryImpl.java | 35 ++++--------------- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryCustom.java b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryCustom.java index 3b8afbc1..0a68eacd 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryCustom.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryCustom.java @@ -1,10 +1,10 @@ package com.fc.shimpyo_be.domain.room.repository; -import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; +import com.fc.shimpyo_be.domain.room.entity.Room; import java.util.List; public interface RoomRepositoryCustom { - List findAllInRoomIdsResponseDto(List roomIds); + List findAllInIdsWithProductAndPrice(List roomIds); } diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java index f7cb9067..9c988291 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/repository/RoomRepositoryImpl.java @@ -1,18 +1,14 @@ package com.fc.shimpyo_be.domain.room.repository; -import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; -import com.querydsl.core.types.Projections; -import com.querydsl.core.types.dsl.Expressions; -import com.querydsl.core.types.dsl.StringExpression; -import com.querydsl.core.types.dsl.TimePath; +import com.fc.shimpyo_be.domain.room.entity.Room; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; -import java.time.LocalTime; import java.util.List; import static com.fc.shimpyo_be.domain.product.entity.QProduct.product; import static com.fc.shimpyo_be.domain.room.entity.QRoom.room; +import static com.fc.shimpyo_be.domain.room.entity.QRoomPrice.roomPrice; @RequiredArgsConstructor public class RoomRepositoryImpl implements RoomRepositoryCustom { @@ -20,30 +16,11 @@ public class RoomRepositoryImpl implements RoomRepositoryCustom { private final JPAQueryFactory jpaQueryFactory; @Override - public List findAllInRoomIdsResponseDto(List roomIds) { - return jpaQueryFactory.select( - Projections.constructor( - RoomWithProductResponseDto.class, - product.id.as("productId"), - product.name.as("productName"), - product.thumbnail.as("productThumbnail"), - product.address.as("productAddress"), - room.id.as("roomId"), - room.name.as("roomName"), - room.standard, - room.capacity, - convertTimeToString(room.checkIn).as("checkIn"), - convertTimeToString(room.checkOut).as("checkOut"), - room.price - ) - ) - .from(room) - .join(room.product, product) + public List findAllInIdsWithProductAndPrice(List roomIds) { + return jpaQueryFactory.selectFrom(room) + .join(room.product, product).fetchJoin() + .join(room.price, roomPrice).fetchJoin() .where(room.id.in(roomIds)) .fetch(); } - - private StringExpression convertTimeToString(TimePath time) { - return Expressions.stringTemplate("TO_CHAR({0}, 'HH24:MI')", time); - } } From 245b16c37ca7b2235577d53154f4f7b4c4b5acb6 Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 12 Dec 2023 05:18:11 +0900 Subject: [PATCH 09/12] =?UTF-8?q?#92=20refactor:=20=EA=B4=80=EB=A0=A8=20DT?= =?UTF-8?q?O=EC=97=90=20@Builder=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20RoomWi?= =?UTF-8?q?thProductResponseDto=EC=97=90=20'productDetailAddress'=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/GetRoomListWithProductInfoRequestDto.java | 2 ++ .../dto/response/RoomListWithProductInfoResponseDto.java | 3 +++ .../room/dto/response/RoomWithProductResponseDto.java | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/dto/request/GetRoomListWithProductInfoRequestDto.java b/src/main/java/com/fc/shimpyo_be/domain/room/dto/request/GetRoomListWithProductInfoRequestDto.java index bbcb83c3..0c5082ec 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/dto/request/GetRoomListWithProductInfoRequestDto.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/dto/request/GetRoomListWithProductInfoRequestDto.java @@ -1,9 +1,11 @@ package com.fc.shimpyo_be.domain.room.dto.request; import jakarta.validation.constraints.Size; +import lombok.Builder; import java.util.List; +@Builder public record GetRoomListWithProductInfoRequestDto( @Size(min = 1, max = 3, message = "최소 1개, 최대 3개의 객실 식별자 정보가 필요합니다.") List roomIds diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomListWithProductInfoResponseDto.java b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomListWithProductInfoResponseDto.java index 11463903..467e9774 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomListWithProductInfoResponseDto.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomListWithProductInfoResponseDto.java @@ -1,7 +1,10 @@ package com.fc.shimpyo_be.domain.room.dto.response; +import lombok.Builder; + import java.util.List; +@Builder public record RoomListWithProductInfoResponseDto( List rooms ) { diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java index cef3cd5a..bcf2ad7d 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/dto/response/RoomWithProductResponseDto.java @@ -1,16 +1,20 @@ package com.fc.shimpyo_be.domain.room.dto.response; +import lombok.Builder; + +@Builder public record RoomWithProductResponseDto( Long productId, String productName, String productThumbnail, String productAddress, + String productDetailAddress, Long roomId, String roomName, Integer standard, Integer capacity, String checkIn, String checkOut, - Integer price + Long price ) { } From e89f1c128c38bf256dc31ccc1487e7658e712407 Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 12 Dec 2023 05:19:58 +0900 Subject: [PATCH 10/12] =?UTF-8?q?#92=20feat:=20RoomMapper=EC=97=90=20toRoo?= =?UTF-8?q?mWithProductResponse=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/room/util/RoomMapper.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/util/RoomMapper.java b/src/main/java/com/fc/shimpyo_be/domain/room/util/RoomMapper.java index f9ecb1dc..c07f475e 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/util/RoomMapper.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/util/RoomMapper.java @@ -1,9 +1,13 @@ package com.fc.shimpyo_be.domain.room.util; +import com.fc.shimpyo_be.domain.product.entity.Address; +import com.fc.shimpyo_be.domain.product.entity.Product; import com.fc.shimpyo_be.domain.room.dto.response.RoomOptionResponse; import com.fc.shimpyo_be.domain.room.dto.response.RoomResponse; +import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; import com.fc.shimpyo_be.domain.room.entity.Room; import com.fc.shimpyo_be.domain.room.entity.RoomOption; +import com.fc.shimpyo_be.global.util.DateTimeUtil; import com.fc.shimpyo_be.global.util.PricePickerByDateUtil; public class RoomMapper { @@ -46,4 +50,24 @@ public static RoomOptionResponse toRoomOptionResponse(RoomOption roomOption) { .refrigerator(roomOption.isRefrigerator()) .build(); } + + public static RoomWithProductResponseDto toRoomWithProductResponse(Room room) { + Product product = room.getProduct(); + Address productAddress = product.getAddress(); + + return RoomWithProductResponseDto.builder() + .productId(product.getId()) + .productName(product.getName()) + .productThumbnail(product.getThumbnail()) + .productAddress(productAddress.getAddress()) + .productDetailAddress(productAddress.getDetailAddress()) + .roomId(room.getId()) + .roomName(room.getName()) + .standard(room.getStandard()) + .capacity(room.getCapacity()) + .checkIn(DateTimeUtil.toString(room.getCheckIn())) + .checkOut(DateTimeUtil.toString(room.getCheckOut())) + .price(PricePickerByDateUtil.getPrice(room)) + .build(); + } } From e212e0d995767eb742e8cca09ab1761a7ac326b0 Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 12 Dec 2023 05:22:07 +0900 Subject: [PATCH 11/12] =?UTF-8?q?#92=20refactor:=20=EB=A3=B8=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8A=94=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=9D=B4=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8A=94=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fc/shimpyo_be/domain/room/service/RoomService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/fc/shimpyo_be/domain/room/service/RoomService.java b/src/main/java/com/fc/shimpyo_be/domain/room/service/RoomService.java index b45dd8c5..b843d48a 100644 --- a/src/main/java/com/fc/shimpyo_be/domain/room/service/RoomService.java +++ b/src/main/java/com/fc/shimpyo_be/domain/room/service/RoomService.java @@ -2,6 +2,7 @@ import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; import com.fc.shimpyo_be.domain.room.repository.RoomRepository; +import com.fc.shimpyo_be.domain.room.util.RoomMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -20,7 +21,10 @@ public class RoomService { public List getRoomsWithProductInfo(List roomIds) { log.debug("{} ::: {}", getClass().getSimpleName(), "getRoomsWithProductInfo"); - return roomRepository.findAllInRoomIdsResponseDto(roomIds); + return roomRepository.findAllInIdsWithProductAndPrice(roomIds) + .stream() + .map(RoomMapper::toRoomWithProductResponse) + .toList(); } } From dbd3a92b39b4b71a39fb58e3a6a07fb6e2403932 Mon Sep 17 00:00:00 2001 From: jo0oy Date: Tue, 12 Dec 2023 05:23:38 +0900 Subject: [PATCH 12/12] =?UTF-8?q?#92=20test:=20Test=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=83=9D=EC=84=B1=ED=95=98=EB=8A=94=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20Builder=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20Test=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../room/docs/RoomRestControllerDocsTest.java | 49 +++++++- .../controller/RoomRestControllerTest.java | 48 +++++++- .../unit/repository/RoomRepositoryTest.java | 108 ++++++++++++++---- .../room/unit/service/RoomServiceTest.java | 105 ++++++++++++++--- 4 files changed, 262 insertions(+), 48 deletions(-) diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java index 6dfec851..a0469ae5 100644 --- a/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java +++ b/src/test/java/com/fc/shimpyo_be/domain/room/docs/RoomRestControllerDocsTest.java @@ -42,12 +42,48 @@ void getRoomsWithProductInfo() throws Exception { GetRoomListWithProductInfoRequestDto requestDto = new GetRoomListWithProductInfoRequestDto(roomIds); List rooms = List.of( - new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일 이미지 url", "호텔1 주소", - 1L, "객실1", 2, 4, "14:00", "12:00", 100000), - new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일 이미지 url", "호텔2 주소", - 3L, "객실3", 3, 5, "14:00", "11:30", 120000), - new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일 이미지 url", "호텔3 주소", - 4L, "객실4", 2, 4, "13:00", "11:00", 95000) + RoomWithProductResponseDto.builder() + .productId(1L) + .productName("호텔1") + .productThumbnail("호텔1 썸네일") + .productAddress("호텔1 주소") + .productDetailAddress("호텔1 상세 주소") + .roomId(1L) + .roomName("객실1") + .standard(2) + .capacity(4) + .checkIn("14:00") + .checkOut("12:00") + .price(80000L) + .build(), + RoomWithProductResponseDto.builder() + .productId(2L) + .productName("호텔2") + .productThumbnail("호텔2 썸네일") + .productAddress("호텔2 주소") + .productDetailAddress("호텔2 상세 주소") + .roomId(3L) + .roomName("객실3") + .standard(2) + .capacity(4) + .checkIn("14:00") + .checkOut("11:30") + .price(95000L) + .build(), + RoomWithProductResponseDto.builder() + .productId(3L) + .productName("호텔3") + .productThumbnail("호텔3 썸네일") + .productAddress("호텔3 주소") + .productDetailAddress("호텔3 상세 주소") + .roomId(4L) + .roomName("객실4") + .standard(2) + .capacity(4) + .checkIn("13:00") + .checkOut("11:00") + .price(80000L) + .build() ); given(roomService.getRoomsWithProductInfo(roomIds)) @@ -74,6 +110,7 @@ void getRoomsWithProductInfo() throws Exception { fieldWithPath("data.rooms[].productName").type(JsonFieldType.STRING).description("숙소명"), fieldWithPath("data.rooms[].productThumbnail").type(JsonFieldType.STRING).description("숙소 썸네일 이미지 URL"), fieldWithPath("data.rooms[].productAddress").type(JsonFieldType.STRING).description("숙소 주소"), + fieldWithPath("data.rooms[].productDetailAddress").type(JsonFieldType.STRING).description("숙소 상세 주소"), fieldWithPath("data.rooms[].roomId").type(JsonFieldType.NUMBER).description("객실 식별자"), fieldWithPath("data.rooms[].roomName").type(JsonFieldType.STRING).description("객실명"), fieldWithPath("data.rooms[].standard").type(JsonFieldType.NUMBER).description("기준 인원"), diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java index 87b3800a..6e6f08ca 100644 --- a/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java +++ b/src/test/java/com/fc/shimpyo_be/domain/room/unit/controller/RoomRestControllerTest.java @@ -59,12 +59,48 @@ void getRoomsWithProductInfo_api_test() throws Exception { GetRoomListWithProductInfoRequestDto requestDto = new GetRoomListWithProductInfoRequestDto(roomIds); List rooms = List.of( - new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일", "호텔1 주소", - 1L, "객실1", 2, 4, "14:00", "12:00", 100000), - new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일", "호텔2 주소", - 3L, "객실3", 2, 4, "14:00", "11:30", 120000), - new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일", "호텔3 주소", - 4L, "객실4", 2, 4, "13:00", "11:00", 95000) + RoomWithProductResponseDto.builder() + .productId(1L) + .productName("호텔1") + .productThumbnail("호텔1 썸네일") + .productAddress("호텔1 주소") + .productDetailAddress("호텔1 상세 주소") + .roomId(1L) + .roomName("객실1") + .standard(2) + .capacity(4) + .checkIn("14:00") + .checkOut("12:00") + .price(80000L) + .build(), + RoomWithProductResponseDto.builder() + .productId(2L) + .productName("호텔2") + .productThumbnail("호텔2 썸네일") + .productAddress("호텔2 주소") + .productDetailAddress("호텔2 상세 주소") + .roomId(3L) + .roomName("객실3") + .standard(2) + .capacity(4) + .checkIn("14:00") + .checkOut("11:30") + .price(95000L) + .build(), + RoomWithProductResponseDto.builder() + .productId(3L) + .productName("호텔3") + .productThumbnail("호텔3 썸네일") + .productAddress("호텔3 주소") + .productDetailAddress("호텔3 상세 주소") + .roomId(4L) + .roomName("객실4") + .standard(2) + .capacity(4) + .checkIn("13:00") + .checkOut("11:00") + .price(95000L) + .build() ); given(roomService.getRoomsWithProductInfo(roomIds)) diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/unit/repository/RoomRepositoryTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/unit/repository/RoomRepositoryTest.java index 617092b0..7956401c 100644 --- a/src/test/java/com/fc/shimpyo_be/domain/room/unit/repository/RoomRepositoryTest.java +++ b/src/test/java/com/fc/shimpyo_be/domain/room/unit/repository/RoomRepositoryTest.java @@ -1,14 +1,15 @@ package com.fc.shimpyo_be.domain.room.unit.repository; +import com.fc.shimpyo_be.config.DatabaseCleanUp; +import com.fc.shimpyo_be.config.TestDBCleanerConfig; import com.fc.shimpyo_be.config.TestQuerydslConfig; -import com.fc.shimpyo_be.domain.product.entity.Category; -import com.fc.shimpyo_be.domain.product.entity.Product; +import com.fc.shimpyo_be.domain.product.entity.*; import com.fc.shimpyo_be.domain.product.repository.ProductRepository; -import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; import com.fc.shimpyo_be.domain.room.entity.Room; +import com.fc.shimpyo_be.domain.room.entity.RoomOption; +import com.fc.shimpyo_be.domain.room.entity.RoomPrice; import com.fc.shimpyo_be.domain.room.repository.RoomRepository; import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -21,10 +22,10 @@ import java.util.LinkedList; import java.util.List; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; @Slf4j -@Import(TestQuerydslConfig.class) +@Import({TestQuerydslConfig.class, TestDBCleanerConfig.class}) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @DataJpaTest public class RoomRepositoryTest { @@ -35,57 +36,118 @@ public class RoomRepositoryTest { @Autowired private ProductRepository productRepository; + @Autowired + private DatabaseCleanUp databaseCleanUp; + + private final String[] tableNameArray = { + "product", "room", "product_option", "address", "room_option", "amenity", "room_price" + }; + private List roomIds; @BeforeEach void setUp() { + databaseCleanUp.cleanUp(tableNameArray); + Product product = productRepository.save( Product.builder() .name("호텔") + .thumbnail("호텔 썸네일 url") .description("호텔 설명") - .address("호텔 도로명 주소") + .starAvg(4.2f) .category(Category.TOURIST_HOTEL) - .thumbnail("호텔 이미지 썸네일") - .starAvg(3.5f) + .address( + Address.builder() + .address("호텔 주소") + .detailAddress("호텔 상세 주소") + .mapX(1.0) + .mapY(1.5) + .build() + ) + .productOption( + ProductOption.builder() + .cooking(true) + .foodPlace("음료 가능") + .parking(true) + .pickup(false) + .infoCenter("1500-0000") + .build() + ) + .amenity( + Amenity.builder() + .barbecue(false) + .beauty(true) + .beverage(true) + .fitness(true) + .bicycle(false) + .campfire(false) + .karaoke(true) + .publicBath(true) + .publicPc(true) + .seminar(false) + .sports(false) + .build() + ) .build() ); roomIds = new LinkedList<>(); for (int i = 1; i <= 5; i++) { + String roomName = "호텔 객실" + i; roomIds.add( roomRepository.save( Room.builder() - .name("호텔 객실 " + i) - .description("객실 설명") .product(product) + .name(roomName) + .description(roomName + " 설명") .standard(2) .capacity(4) - .checkIn(LocalTime.of(13, 0)) + .checkIn(LocalTime.of(14, 0)) .checkOut(LocalTime.of(12, 0)) - .price(Integer.parseInt(String.format("1%d0000", i))) + .price( + RoomPrice.builder() + .offWeekDaysMinFee(75000) + .offWeekendMinFee(85000) + .peakWeekDaysMinFee(100000) + .peakWeekendMinFee(120000) + .build() + ) + .roomOption( + RoomOption.builder() + .cooking(true) + .airCondition(true) + .bath(true) + .bathFacility(true) + .pc(false) + .diningTable(true) + .hairDryer(true) + .homeTheater(false) + .internet(true) + .cable(false) + .refrigerator(true) + .sofa(true) + .toiletries(true) + .tv(true) + .build() + ) .build() ).getId() ); } } - @DisplayName("findAllInRoomIdsResponseDto 테스트") + @DisplayName("findAllInIdsWithProductAndPrice 테스트") @Test - void findAllInRoomIdsResponseDto() { + void findAllInIdsWithProductAndPrice() { //given //when - List result = roomRepository.findAllInRoomIdsResponseDto(roomIds); + List result = roomRepository.findAllInIdsWithProductAndPrice(roomIds); //then assertThat(result).hasSize(5); - assertThat(result.get(0).checkIn()).isInstanceOf(String.class); - } - - @AfterEach - void tearDown() { - roomRepository.deleteAll(); - productRepository.deleteAll(); + assertThat(result.get(0).getProduct().getId()).isEqualTo(1); + assertThat(result.get(0).getPrice()).isNotNull(); } } diff --git a/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java b/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java index d3278e94..0bd36745 100644 --- a/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java +++ b/src/test/java/com/fc/shimpyo_be/domain/room/unit/service/RoomServiceTest.java @@ -1,6 +1,10 @@ package com.fc.shimpyo_be.domain.room.unit.service; +import com.fc.shimpyo_be.domain.product.entity.*; import com.fc.shimpyo_be.domain.room.dto.response.RoomWithProductResponseDto; +import com.fc.shimpyo_be.domain.room.entity.Room; +import com.fc.shimpyo_be.domain.room.entity.RoomOption; +import com.fc.shimpyo_be.domain.room.entity.RoomPrice; import com.fc.shimpyo_be.domain.room.repository.RoomRepository; import com.fc.shimpyo_be.domain.room.service.RoomService; import org.junit.jupiter.api.DisplayName; @@ -10,9 +14,11 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.time.LocalTime; +import java.util.ArrayList; import java.util.List; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -26,23 +32,96 @@ public class RoomServiceTest { @Mock private RoomRepository roomRepository; - @DisplayName("") + @DisplayName("객실 식별자 리스트에 해당하는 객실과 숙소 정보를 리스트로 반환한다.") @Test void getRoomsWithProductInfo_test() { //given List roomIds = List.of(1L, 3L, 4L); - List rooms = List.of( - new RoomWithProductResponseDto(1L, "호텔1", "호텔1 썸네일", "호텔1 주소", - 1L, "객실1", 2, 4, "14:00", "12:00", 100000), - new RoomWithProductResponseDto(2L, "호텔2", "호텔2 썸네일", "호텔2 주소", - 3L, "객실3", 2, 4, "14:00", "11:30", 120000), - new RoomWithProductResponseDto(3L, "호텔3", "호텔3 썸네일", "호텔3 주소", - 4L, "객실4", 2, 4, "13:00", "11:00", 95000) - ); + Product product = Product.builder() + .name("호텔") + .thumbnail("호텔 썸네일 url") + .description("호텔 설명") + .starAvg(4.2f) + .category(Category.TOURIST_HOTEL) + .address( + Address.builder() + .address("호텔 주소") + .detailAddress("호텔 상세 주소") + .mapX(1.0) + .mapY(1.5) + .build() + ) + .productOption( + ProductOption.builder() + .cooking(true) + .foodPlace("음료 가능") + .parking(true) + .pickup(false) + .infoCenter("1500-0000") + .build() + ) + .amenity( + Amenity.builder() + .barbecue(false) + .beauty(true) + .beverage(true) + .fitness(true) + .bicycle(false) + .campfire(false) + .karaoke(true) + .publicBath(true) + .publicPc(true) + .seminar(false) + .sports(false) + .build() + ) + .build(); - given(roomRepository.findAllInRoomIdsResponseDto(roomIds)) - .willReturn(rooms); + List rooms = new ArrayList<>(); + + for (int i = 1; i <= 3; i++) { + String roomName = "호텔 객실" + i; + rooms.add( + Room.builder() + .product(product) + .name(roomName) + .description(roomName + " 설명") + .standard(2) + .capacity(4) + .checkIn(LocalTime.of(14, 0)) + .checkOut(LocalTime.of(12, 0)) + .price( + RoomPrice.builder() + .offWeekDaysMinFee(75000) + .offWeekendMinFee(85000) + .peakWeekDaysMinFee(100000) + .peakWeekendMinFee(120000) + .build() + ) + .roomOption( + RoomOption.builder() + .cooking(true) + .airCondition(true) + .bath(true) + .bathFacility(true) + .pc(false) + .diningTable(true) + .hairDryer(true) + .homeTheater(false) + .internet(true) + .cable(false) + .refrigerator(true) + .sofa(true) + .toiletries(true) + .tv(true) + .build() + ) + .build() + ); + } + + given(roomRepository.findAllInIdsWithProductAndPrice(roomIds)).willReturn(rooms); //when List result = roomService.getRoomsWithProductInfo(roomIds); @@ -50,6 +129,6 @@ void getRoomsWithProductInfo_test() { //then assertThat(result).hasSize(3); - verify(roomRepository, times(1)).findAllInRoomIdsResponseDto(roomIds); + verify(roomRepository, times(1)).findAllInIdsWithProductAndPrice(roomIds); } }