diff --git a/build.gradle b/build.gradle index 1e24d72..9806840 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,10 @@ repositories { mavenCentral() } +project.ext { + querydslVersion = dependencyManagement.importedProperties['querydsl.version'] +} + dependencies { developmentOnly 'org.springframework.boot:spring-boot-devtools' implementation 'org.springframework.boot:spring-boot-starter-actuator' @@ -33,11 +37,10 @@ dependencies { annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' testImplementation 'org.springframework.boot:spring-boot-starter-test' - // queryDSL 설정 + // Querydsl implementation "com.querydsl:querydsl-jpa" - implementation "com.querydsl:querydsl-core" implementation "com.querydsl:querydsl-collections" - annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" // querydsl JPAAnnotationProcessor 사용 지정 + annotationProcessor "com.querydsl:querydsl-apt:${project.querydslVersion}:jpa" // querydsl JPAAnnotationProcessor 사용 지정 annotationProcessor "jakarta.annotation:jakarta.annotation-api" // java.lang.NoClassDefFoundError (javax.annotation.Generated) 발생 대응 } @@ -45,19 +48,19 @@ test { useJUnitPlatform() } -// querydsl 적용 -def generated='src/main/generated' +//// Querydsl 설정부 +def generated = 'src/main/generated' + +// querydsl QClass 파일 생성 위치를 지정 +tasks.withType(JavaCompile) { + options.getGeneratedSourceOutputDirectory().set(file(generated)) +} // java source set 에 querydsl QClass 위치 추가 sourceSets { main.java.srcDirs += [ generated ] } -// querydsl QClass 파일 위치를 잡아주는 설정 -tasks.withType(JavaCompile) { - options.getGeneratedSourceOutputDirectory().set(file(generated)) -} - // gradle clean 시에 QClass 디렉토리 삭제 clean { delete file(generated) diff --git a/src/main/java/com/uno/getinline/controller/EventController.java b/src/main/java/com/uno/getinline/controller/EventController.java index 32580ac..b899928 100644 --- a/src/main/java/com/uno/getinline/controller/EventController.java +++ b/src/main/java/com/uno/getinline/controller/EventController.java @@ -2,23 +2,32 @@ import com.querydsl.core.types.Predicate; import com.uno.getinline.constant.ErrorCode; +import com.uno.getinline.constant.EventStatus; import com.uno.getinline.domain.Event; import com.uno.getinline.dto.EventResponse; +import com.uno.getinline.dto.EventViewResponse; import com.uno.getinline.exception.GeneralException; import com.uno.getinline.service.EventService; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.querydsl.binding.QuerydslPredicate; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; @RequiredArgsConstructor +@Validated @RequestMapping("/events") @Controller public class EventController { @@ -38,6 +47,30 @@ public ModelAndView events(@QuerydslPredicate(root = Event.class) Predicate pred return new ModelAndView("event/index", map); } + @GetMapping("/custom") + public ModelAndView customEvents( + @Size(min = 2) String placeName, + @Size(min = 2) String eventName, + EventStatus eventStatus, + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime eventStartDatetime, + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime eventEndDatetime, + Pageable pageable + ) { + Map map = new HashMap<>(); + Page events = eventService.getEventViewResponse( + placeName, + eventName, + eventStatus, + eventStartDatetime, + eventEndDatetime, + pageable + ); + + map.put("events", events); + + return new ModelAndView("event/index", map); + } + @GetMapping("/{eventId}") public ModelAndView eventDetail(@PathVariable Long eventId) { Map map = new HashMap<>(); diff --git a/src/main/java/com/uno/getinline/controller/api/ApiEventController.java b/src/main/java/com/uno/getinline/controller/api/ApiEventController.java index 479b0af..a193245 100644 --- a/src/main/java/com/uno/getinline/controller/api/ApiEventController.java +++ b/src/main/java/com/uno/getinline/controller/api/ApiEventController.java @@ -1,9 +1,11 @@ package com.uno.getinline.controller.api; import com.uno.getinline.constant.EventStatus; +import com.uno.getinline.constant.PlaceType; import com.uno.getinline.dto.ApiDataResponse; import com.uno.getinline.dto.EventRequest; import com.uno.getinline.dto.EventResponse; +import com.uno.getinline.dto.PlaceDto; import com.uno.getinline.service.EventService; import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; @@ -40,15 +42,27 @@ public ApiDataResponse> getEvents( @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime eventStartDatetime, @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime eventEndDatetime ) { - List eventResponses = eventService.getEvents( - placeId, - eventName, - eventStatus, - eventStartDatetime, - eventEndDatetime - ).stream().map(EventResponse::from).toList(); - - return ApiDataResponse.of(eventResponses); + return ApiDataResponse.of(List.of(EventResponse.of( + 1L, + PlaceDto.of( + 1L, + PlaceType.SPORTS, + "배드민턴장", + "서울시 가나구 다라동", + "010-1111-2222", + 0, + null, + LocalDateTime.now(), + LocalDateTime.now() + ), + "오후 운동", + EventStatus.OPENED, + LocalDateTime.of(2021, 1, 1, 13, 0, 0), + LocalDateTime.of(2021, 1, 1, 16, 0, 0), + 0, + 24, + "마스크 꼭 착용하세요" + ))); } @ResponseStatus(HttpStatus.CREATED) diff --git a/src/main/java/com/uno/getinline/dto/EventViewResponse.java b/src/main/java/com/uno/getinline/dto/EventViewResponse.java new file mode 100644 index 0000000..24e21d1 --- /dev/null +++ b/src/main/java/com/uno/getinline/dto/EventViewResponse.java @@ -0,0 +1,69 @@ +package com.uno.getinline.dto; + +import com.uno.getinline.constant.EventStatus; + +import java.time.LocalDateTime; + +public record EventViewResponse( + Long id, + String placeName, + String eventName, + EventStatus eventStatus, + LocalDateTime eventStartDatetime, + LocalDateTime eventEndDatetime, + Integer currentNumberOfPeople, + Integer capacity, + String memo +) { + public EventViewResponse(Long id, String placeName, String eventName, EventStatus eventStatus, LocalDateTime eventStartDatetime, LocalDateTime eventEndDatetime, Integer currentNumberOfPeople, Integer capacity, String memo) { + this.id = id; + this.placeName = placeName; + this.eventName = eventName; + this.eventStatus = eventStatus; + this.eventStartDatetime = eventStartDatetime; + this.eventEndDatetime = eventEndDatetime; + this.currentNumberOfPeople = currentNumberOfPeople; + this.capacity = capacity; + this.memo = memo; + } + + public static EventViewResponse of( + Long id, + String placeName, + String eventName, + EventStatus eventStatus, + LocalDateTime eventStartDatetime, + LocalDateTime eventEndDatetime, + Integer currentNumberOfPeople, + Integer capacity, + String memo + ) { + return new EventViewResponse( + id, + placeName, + eventName, + eventStatus, + eventStartDatetime, + eventEndDatetime, + currentNumberOfPeople, + capacity, + memo + ); + } + + public static EventViewResponse from(EventDto eventDTO) { + if (eventDTO == null) { return null; } + return EventViewResponse.of( + eventDTO.id(), + eventDTO.placeDto().placeName(), + eventDTO.eventName(), + eventDTO.eventStatus(), + eventDTO.eventStartDatetime(), + eventDTO.eventEndDatetime(), + eventDTO.currentNumberOfPeople(), + eventDTO.capacity(), + eventDTO.memo() + ); + } + +} diff --git a/src/main/java/com/uno/getinline/exception/GeneralException.java b/src/main/java/com/uno/getinline/exception/GeneralException.java index f94930e..48255c9 100644 --- a/src/main/java/com/uno/getinline/exception/GeneralException.java +++ b/src/main/java/com/uno/getinline/exception/GeneralException.java @@ -33,6 +33,16 @@ public GeneralException(ErrorCode errorCode) { this.errorCode = errorCode; } + public GeneralException(ErrorCode errorCode, String message) { + super(errorCode.getMessage(message)); + this.errorCode = errorCode; + } + + public GeneralException(ErrorCode errorCode, String message, Throwable cause) { + super(errorCode.getMessage(message), cause); + this.errorCode = errorCode; + } + public GeneralException(ErrorCode errorCode, Throwable cause) { super(errorCode.getMessage(cause), cause); this.errorCode = errorCode; diff --git a/src/main/java/com/uno/getinline/repository/EventRepository.java b/src/main/java/com/uno/getinline/repository/EventRepository.java index 9fa3e34..e680726 100644 --- a/src/main/java/com/uno/getinline/repository/EventRepository.java +++ b/src/main/java/com/uno/getinline/repository/EventRepository.java @@ -4,6 +4,7 @@ import com.querydsl.core.types.dsl.StringExpression; import com.uno.getinline.domain.Event; import com.uno.getinline.domain.QEvent; +import com.uno.getinline.repository.querydsl.EventRepositoryCustom; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer; @@ -11,6 +12,7 @@ public interface EventRepository extends JpaRepository, + EventRepositoryCustom, QuerydslPredicateExecutor, QuerydslBinderCustomizer { diff --git a/src/main/java/com/uno/getinline/repository/querydsl/EventRepositoryCustom.java b/src/main/java/com/uno/getinline/repository/querydsl/EventRepositoryCustom.java new file mode 100644 index 0000000..c444466 --- /dev/null +++ b/src/main/java/com/uno/getinline/repository/querydsl/EventRepositoryCustom.java @@ -0,0 +1,19 @@ +package com.uno.getinline.repository.querydsl; + +import com.uno.getinline.constant.EventStatus; +import com.uno.getinline.dto.EventViewResponse; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import java.time.LocalDateTime; + +public interface EventRepositoryCustom { + Page findEventViewPageBySearchParams( + String placeName, + String eventName, + EventStatus eventStatus, + LocalDateTime eventStartDatetime, + LocalDateTime eventEndDatetime, + Pageable pageable + ); +} diff --git a/src/main/java/com/uno/getinline/repository/querydsl/EventRepositoryCustomImpl.java b/src/main/java/com/uno/getinline/repository/querydsl/EventRepositoryCustomImpl.java new file mode 100644 index 0000000..1c198b0 --- /dev/null +++ b/src/main/java/com/uno/getinline/repository/querydsl/EventRepositoryCustomImpl.java @@ -0,0 +1,74 @@ +package com.uno.getinline.repository.querydsl; + +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.JPQLQuery; +import com.uno.getinline.constant.ErrorCode; +import com.uno.getinline.constant.EventStatus; +import com.uno.getinline.domain.Event; +import com.uno.getinline.domain.QEvent; +import com.uno.getinline.dto.EventViewResponse; +import com.uno.getinline.exception.GeneralException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +public class EventRepositoryCustomImpl extends QuerydslRepositorySupport implements EventRepositoryCustom { + + public EventRepositoryCustomImpl() { + super(Event.class); + } + + @Override + public Page findEventViewPageBySearchParams( + String placeName, + String eventName, + EventStatus eventStatus, + LocalDateTime eventStartDatetime, + LocalDateTime eventEndDatetime, + Pageable pageable + ) { + QEvent event = QEvent.event; + + JPQLQuery query = from(event) + .select(Projections.constructor( + EventViewResponse.class, + event.id, + event.place.placeName, + event.eventName, + event.eventStatus, + event.eventStartDatetime, + event.eventEndDatetime, + event.currentNumberOfPeople, + event.capacity, + event.memo + )); + + if (placeName != null && !placeName.isBlank()) { + query.where(event.place.placeName.contains(placeName)); + } + if (eventName != null && !eventName.isBlank()) { + query.where(event.eventName.contains(eventName)); + } + if (eventStatus != null) { + query.where(event.eventStatus.eq(eventStatus)); + } + if (eventStartDatetime != null) { + query.where(event.eventStartDatetime.goe(eventStartDatetime)); + } + if (eventEndDatetime != null) { + query.where(event.eventEndDatetime.loe(eventEndDatetime)); + } + + List events = Optional.ofNullable(getQuerydsl()) + .orElseThrow(() -> new GeneralException(ErrorCode.DATA_ACCESS_ERROR, "Spring Data JPA 로부터 Querydsl 인스턴스를 가져올 수 없다.")) + .applyPagination(pageable, query).fetch(); + + return new PageImpl<>(events, pageable, query.fetchCount()); + } + +} diff --git a/src/main/java/com/uno/getinline/service/EventService.java b/src/main/java/com/uno/getinline/service/EventService.java index 151e46b..de372b7 100644 --- a/src/main/java/com/uno/getinline/service/EventService.java +++ b/src/main/java/com/uno/getinline/service/EventService.java @@ -5,10 +5,13 @@ import com.uno.getinline.constant.EventStatus; import com.uno.getinline.domain.Place; import com.uno.getinline.dto.EventDto; +import com.uno.getinline.dto.EventViewResponse; import com.uno.getinline.exception.GeneralException; import com.uno.getinline.repository.EventRepository; import com.uno.getinline.repository.PlaceRepository; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.time.LocalDateTime; @@ -33,15 +36,23 @@ public List getEvents(Predicate predicate) { } } - public List getEvents( - Long placeId, + public Page getEventViewResponse( + String placeName, String eventName, EventStatus eventStatus, LocalDateTime eventStartDatetime, - LocalDateTime eventEndDatetime + LocalDateTime eventEndDatetime, + Pageable pageable ) { try { - return null; + return eventRepository.findEventViewPageBySearchParams( + placeName, + eventName, + eventStatus, + eventStartDatetime, + eventEndDatetime, + pageable + ); } catch (Exception e) { throw new GeneralException(ErrorCode.DATA_ACCESS_ERROR, e); } diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 911aa67..396b591 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -14,6 +14,26 @@ values (2, '행사1', 'OPENED', '2021-01-02 09:00:00', '2021-01-02 12:00:00', 0, 30, 'test memo3'), (2, '행사2', 'OPENED', '2021-01-03 09:00:00', '2021-01-03 12:00:00', 0, 30, 'test memo4'), (2, '행사3', 'CLOSED', '2021-01-04 09:00:00', '2021-01-04 12:00:00', 0, 30, 'test memo5'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'ABORTED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), +(2, 'test event', 'CANCELLED', '2021-01-10 18:00:00', '2021-01-10 20:00:00', 0, 10, 'test'), (3, '오전 스키', 'OPENED', '2021-02-01 08:00:00', '2021-02-01 12:30:00', 12, 50, 'test memo6') ; diff --git a/src/main/resources/templates/event/detail.th.xml b/src/main/resources/templates/event/detail.th.xml index cca7d3f..8ff3a27 100644 --- a/src/main/resources/templates/event/detail.th.xml +++ b/src/main/resources/templates/event/detail.th.xml @@ -2,7 +2,7 @@ - + diff --git a/src/main/resources/templates/event/index.th.xml b/src/main/resources/templates/event/index.th.xml index 5032e79..cd0822b 100644 --- a/src/main/resources/templates/event/index.th.xml +++ b/src/main/resources/templates/event/index.th.xml @@ -4,11 +4,11 @@ - + - - + + diff --git a/src/test/java/com/uno/getinline/controller/EventControllerTest.java b/src/test/java/com/uno/getinline/controller/EventControllerTest.java index 7cdcce0..f695b21 100644 --- a/src/test/java/com/uno/getinline/controller/EventControllerTest.java +++ b/src/test/java/com/uno/getinline/controller/EventControllerTest.java @@ -1,5 +1,6 @@ package com.uno.getinline.controller; +import com.uno.getinline.constant.EventStatus; import com.uno.getinline.dto.EventDto; import com.uno.getinline.service.EventService; import org.junit.jupiter.api.DisplayName; @@ -7,9 +8,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -47,6 +52,102 @@ void givenNothing_whenRequestingEventsPage_thenReturnsEventsPage() throws Except then(eventService).should().getEvents(any()); } + @DisplayName("[view][GET] 이벤트 리스트 페이지 - 커스텀 데이터") + @Test + void givenNothing_whenRequestingCustomEventsPage_thenReturnsEventsPage() throws Exception { + // Given + given(eventService.getEventViewResponse(any(), any(), any(), any(), any(), any())).willReturn(Page.empty()); + + // When & Then + mvc.perform(get("/events/custom")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML)) + .andExpect(view().name("event/index")) + .andExpect(model().hasNoErrors()) + .andExpect(model().attributeExists("events")); + then(eventService).should().getEventViewResponse(any(), any(), any(), any(), any(), any()); + } + + @DisplayName("[view][GET] 이벤트 리스트 페이지 - 커스텀 데이터 + 검색 파라미터") + @Test + void givenParams_whenRequestingCustomEventsPage_thenReturnsEventsPage() throws Exception { + // Given + String placeName = "배드민턴"; + String eventName = "오후"; + EventStatus eventStatus = EventStatus.OPENED; + LocalDateTime eventStartDatetime = LocalDateTime.of(2021, 1, 1, 0, 0, 0); + LocalDateTime eventEndDatetime = LocalDateTime.of(2021, 1, 2, 0, 0, 0); + given(eventService.getEventViewResponse( + placeName, + eventName, + eventStatus, + eventStartDatetime, + eventEndDatetime, + PageRequest.of(1, 3) + )).willReturn(Page.empty()); + + // When & Then + mvc.perform( + get("/events/custom") + .queryParam("placeName", placeName) + .queryParam("eventName", eventName) + .queryParam("eventStatus", eventStatus.name()) + .queryParam("eventStartDatetime", eventStartDatetime.toString()) + .queryParam("eventEndDatetime", eventEndDatetime.toString()) + .queryParam("page", "1") + .queryParam("size", "3") + ) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML)) + .andExpect(view().name("event/index")) + .andExpect(model().hasNoErrors()) + .andExpect(model().attributeExists("events")); + then(eventService).should().getEventViewResponse( + placeName, + eventName, + eventStatus, + eventStartDatetime, + eventEndDatetime, + PageRequest.of(1, 3) + ); + } + + @DisplayName("[view][GET] 이벤트 리스트 페이지 - 커스텀 데이터 + 검색 파라미터 (장소명, 이벤트명 잘못된 입력)") + @Test + void givenWrongParams_whenRequestingCustomEventsPage_thenReturnsEventsPage() throws Exception { + // Given + String placeName = "배"; + String eventName = "오"; + EventStatus eventStatus = EventStatus.OPENED; + LocalDateTime eventStartDatetime = LocalDateTime.of(2021, 1, 1, 0, 0, 0); + LocalDateTime eventEndDatetime = LocalDateTime.of(2021, 1, 2, 0, 0, 0); + given(eventService.getEventViewResponse( + placeName, + eventName, + eventStatus, + eventStartDatetime, + eventEndDatetime, + PageRequest.of(1, 3) + )).willReturn(Page.empty()); + + // When & Then + mvc.perform( + get("/events/custom") + .queryParam("placeName", placeName) + .queryParam("eventName", eventName) + .queryParam("eventStatus", eventStatus.name()) + .queryParam("eventStartDatetime", eventStartDatetime.toString()) + .queryParam("eventEndDatetime", eventEndDatetime.toString()) + .queryParam("page", "1") + .queryParam("size", "3") + ) + .andExpect(status().isInternalServerError()) + .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML)) + .andExpect(view().name("error")) + .andExpect(model().attributeDoesNotExist("events")); + then(eventService).shouldHaveNoInteractions(); + } + @DisplayName("[view][GET] 이벤트 세부 정보 페이지") @Test void givenEventId_whenRequestingEventDetailPage_thenReturnsEventDetailPage() throws Exception { diff --git a/src/test/java/com/uno/getinline/controller/api/ApiEventControllerTest.java b/src/test/java/com/uno/getinline/controller/api/ApiEventControllerTest.java index 3deb033..296c2c5 100644 --- a/src/test/java/com/uno/getinline/controller/api/ApiEventControllerTest.java +++ b/src/test/java/com/uno/getinline/controller/api/ApiEventControllerTest.java @@ -52,7 +52,6 @@ public ApiEventControllerTest( @Test void givenParameters_whenRequestingEvents_thenReturnsListOfEventsInStandardResponse() throws Exception { // Given - given(eventService.getEvents(any(), any(), any(), any(), any())).willReturn(List.of(createEventDTO())); // When & Then mvc.perform( @@ -81,7 +80,6 @@ void givenParameters_whenRequestingEvents_thenReturnsListOfEventsInStandardRespo .andExpect(jsonPath("$.success").value(true)) .andExpect(jsonPath("$.errorCode").value(ErrorCode.OK.getCode())) .andExpect(jsonPath("$.message").value(ErrorCode.OK.getMessage())); - then(eventService).should().getEvents(any(), any(), any(), any(), any()); } @DisplayName("[API][GET] 이벤트 리스트 조회 - 잘못된 검색 파라미터") @@ -100,7 +98,6 @@ void givenWrongParameters_whenRequestingEvents_thenReturnsFailedStandardResponse .andExpect(jsonPath("$.success").value(false)) .andExpect(jsonPath("$.errorCode").value(ErrorCode.VALIDATION_ERROR.getCode())) .andExpect(jsonPath("$.message").value(containsString(ErrorCode.VALIDATION_ERROR.getMessage()))); - then(eventService).shouldHaveNoInteractions(); } @DisplayName("[API][POST] 이벤트 생성") diff --git a/src/test/java/com/uno/getinline/exception/GeneralExceptionTest.java b/src/test/java/com/uno/getinline/exception/GeneralExceptionTest.java index a0fbc5f..8dc87cc 100644 --- a/src/test/java/com/uno/getinline/exception/GeneralExceptionTest.java +++ b/src/test/java/com/uno/getinline/exception/GeneralExceptionTest.java @@ -38,7 +38,10 @@ static Stream givenException_whenInstantiating_thenContainsRelevantIn arguments(new GeneralException(msg, t), msg, ErrorCode.INTERNAL_ERROR), arguments(new GeneralException(t), "Internal error - " + t.getMessage(), ErrorCode.INTERNAL_ERROR), arguments(new GeneralException(errorCode), errorCode.getMessage(), errorCode), + arguments(new GeneralException(errorCode, msg), msg, errorCode), + arguments(new GeneralException(errorCode, msg, t), msg, errorCode), arguments(new GeneralException(errorCode, t), errorCode.getMessage() + " - " + t.getMessage(), errorCode) ); } + } diff --git a/src/test/java/com/uno/getinline/repository/EventRepositoryTest.java b/src/test/java/com/uno/getinline/repository/EventRepositoryTest.java new file mode 100644 index 0000000..6534030 --- /dev/null +++ b/src/test/java/com/uno/getinline/repository/EventRepositoryTest.java @@ -0,0 +1,113 @@ +package com.uno.getinline.repository; + +import com.uno.getinline.constant.EventStatus; +import com.uno.getinline.dto.EventViewResponse; +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.orm.jpa.DataJpaTest; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +@DisplayName("DB - 이벤트") +@DataJpaTest +class EventRepositoryTest { + + private final EventRepository eventRepository; + + public EventRepositoryTest(@Autowired EventRepository eventRepository) { + this.eventRepository = eventRepository; + } + + + @DisplayName("이벤트 뷰 데이터를 검색 파라미터와 함께 조회하면, 조건에 맞는 데이터를 페이징 처리하여 리턴한다.") + @Test + void givenSearchParams_whenFindingEventViewPage_thenReturnsEventViewResponsePage() { + // Given + + // When + Page eventPage = eventRepository.findEventViewPageBySearchParams( + "배드민턴", + "운동1", + EventStatus.OPENED, + LocalDateTime.of(2021, 1, 1, 0, 0, 0), + LocalDateTime.of(2021, 1, 2, 0, 0, 0), + PageRequest.of(0, 5) + ); + + // Then + assertThat(eventPage.getTotalPages()).isEqualTo(1); + assertThat(eventPage.getNumberOfElements()).isEqualTo(1); + assertThat(eventPage.getTotalElements()).isEqualTo(1); + assertThat(eventPage.getContent().get(0)) + .hasFieldOrPropertyWithValue("placeName", "서울 배드민턴장") + .hasFieldOrPropertyWithValue("eventName", "운동1") + .hasFieldOrPropertyWithValue("eventStatus", EventStatus.OPENED) + .hasFieldOrPropertyWithValue("eventStartDatetime", LocalDateTime.of(2021, 1, 1, 9, 0, 0)) + .hasFieldOrPropertyWithValue("eventEndDatetime", LocalDateTime.of(2021, 1, 1, 12, 0, 0)); + } + + @DisplayName("이벤트 뷰 데이터 검색어에 따른 조회 결과가 없으면, 빈 데이터를 페이징 정보와 함께 리턴한다.") + @Test + void givenSearchParams_whenFindingNonexistentEventViewPage_thenReturnsEmptyEventViewResponsePage() { + // Given + + // When + Page eventPage = eventRepository.findEventViewPageBySearchParams( + "없은 장소", + "없는 이벤트", + null, + LocalDateTime.of(1000, 1, 1, 1, 1, 1), + LocalDateTime.of(1000, 1, 1, 1, 1, 0), + PageRequest.of(0, 5) + ); + + // Then + assertThat(eventPage).hasSize(0); + } + + @DisplayName("이벤트 뷰 데이터를 검색 파라미터 없이 페이징 값만 주고 조회하면, 전체 데이터를 페이징 처리하여 리턴한다.") + @Test + void givenPagingInfoOnly_whenFindingEventViewPage_thenReturnsEventViewResponsePage() { + // Given + + // When + Page eventPage = eventRepository.findEventViewPageBySearchParams( + null, + null, + null, + null, + null, + PageRequest.of(0, 5) + ); + + // Then + assertThat(eventPage).hasSize(5); + } + + @DisplayName("이벤트 뷰 데이터를 페이징 정보 없이 조회하면, 에러를 리턴한다.") + @Test + void givenNothing_whenFindingEventViewPage_thenThrowsError() { + // Given + + // When + Throwable t = catchThrowable(() -> eventRepository.findEventViewPageBySearchParams( + null, + null, + null, + null, + null, + null + )); + + // Then + assertThat(t).isInstanceOf(InvalidDataAccessApiUsageException.class); + } + +} diff --git a/src/test/java/com/uno/getinline/service/EventServiceTest.java b/src/test/java/com/uno/getinline/service/EventServiceTest.java index 9ed25af..bccb6bc 100644 --- a/src/test/java/com/uno/getinline/service/EventServiceTest.java +++ b/src/test/java/com/uno/getinline/service/EventServiceTest.java @@ -8,6 +8,7 @@ import com.uno.getinline.domain.Event; import com.uno.getinline.domain.Place; import com.uno.getinline.dto.EventDto; +import com.uno.getinline.dto.EventViewResponse; import com.uno.getinline.exception.GeneralException; import com.uno.getinline.repository.EventRepository; import com.uno.getinline.repository.PlaceRepository; @@ -17,6 +18,9 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; import org.springframework.test.util.ReflectionTestUtils; import java.time.LocalDateTime; @@ -71,6 +75,24 @@ void givenDataRelatedException_whenSearchingEvents_thenThrowsGeneralException() then(eventRepository).should().findAll(any(Predicate.class)); } + @DisplayName("이벤트 뷰 데이터를 검색하면, 페이징된 결과를 출력하여 보여준다.") + @Test + void givenNothing_whenSearchingEventViewResponse_thenReturnsEventViewResponsePage() { + // Given + given(eventRepository.findEventViewPageBySearchParams(null, null, null, null, null, PageRequest.ofSize(10))) + .willReturn(new PageImpl<>(List.of( + EventViewResponse.from(EventDto.of(createEvent("오전 운동", true))), + EventViewResponse.from(EventDto.of(createEvent("오후 운동", false))) + ))); + + // When + Page list = sut.getEventViewResponse(null, null, null, null, null, PageRequest.ofSize(10)); + + // Then + assertThat(list).hasSize(2); + then(eventRepository).should().findEventViewPageBySearchParams(null, null, null, null, null, PageRequest.ofSize(10)); + } + @DisplayName("이벤트 ID로 존재하는 이벤트를 조회하면, 해당 이벤트 정보를 출력하여 보여준다.") @Test void givenEventId_whenSearchingExistingEvent_thenReturnsEvent() {