diff --git a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt index b9559fd2..9b2ff06b 100644 --- a/src/main/java/roomescape/reservation/business/ReservationTimeService.kt +++ b/src/main/java/roomescape/reservation/business/ReservationTimeService.kt @@ -28,12 +28,9 @@ class ReservationTimeService( @Transactional(readOnly = true) - fun findAllTimes(): ReservationTimesResponse { - val response = reservationTimeRepository.findAll() - .map { it.toResponse() } + fun findAllTimes(): ReservationTimesResponse = reservationTimeRepository.findAll() + .toResponses() - return ReservationTimesResponse(response) - } @Transactional fun addTime(reservationTimeRequest: ReservationTimeRequest): ReservationTimeResponse { diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt b/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt index 299c727b..e4d09e5d 100644 --- a/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt +++ b/src/main/java/roomescape/reservation/web/ReservationTimeDTO.kt @@ -1,6 +1,7 @@ package roomescape.reservation.web import io.swagger.v3.oas.annotations.media.Schema +import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity import java.time.LocalTime @Schema(name = "예약 시간 저장 요청", description = "예약 시간 저장 요청시 사용됩니다.") @@ -38,3 +39,7 @@ data class ReservationTimesResponse( @field:Schema(description = "모든 시간 목록") val times: List ) + +fun List.toResponses(): ReservationTimesResponse = ReservationTimesResponse( + this.map { it.toResponse() } +) diff --git a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt index 2db88ab0..cb4a9342 100644 --- a/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt +++ b/src/test/java/roomescape/reservation/business/ReservationTimeServiceTest.kt @@ -1,93 +1,92 @@ -package roomescape.reservation.business; +package roomescape.reservation.business -import static org.assertj.core.api.Assertions.*; +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import org.springframework.data.repository.findByIdOrNull +import org.springframework.http.HttpStatus +import roomescape.common.exception.ErrorType +import roomescape.common.exception.RoomescapeException +import roomescape.reservation.infrastructure.persistence.ReservationRepository +import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository +import roomescape.reservation.web.ReservationTimeRequest +import roomescape.util.ReservationTimeFixture +import java.time.LocalTime -import java.time.LocalDateTime; -import java.time.LocalTime; +class ReservationTimeServiceTest : FunSpec({ + val reservationTimeRepository: ReservationTimeRepository = mockk() + val reservationRepository: ReservationRepository = mockk() -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.context.annotation.Import; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.Sql.ExecutionPhase; + val reservationTimeService = ReservationTimeService( + reservationTimeRepository = reservationTimeRepository, + reservationRepository = reservationRepository + ) -import roomescape.common.exception.RoomescapeException; -import roomescape.member.infrastructure.persistence.MemberEntity; -import roomescape.member.infrastructure.persistence.MemberRepository; -import roomescape.member.infrastructure.persistence.Role; -import roomescape.reservation.infrastructure.persistence.ReservationEntity; -import roomescape.reservation.infrastructure.persistence.ReservationRepository; -import roomescape.reservation.infrastructure.persistence.ReservationStatus; -import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; -import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; -import roomescape.reservation.web.ReservationTimeRequest; -import roomescape.theme.infrastructure.persistence.ThemeEntity; -import roomescape.theme.infrastructure.persistence.ThemeRepository; + context("findTimeById") { + test("시간을 찾을 수 없으면 400 에러를 던진다.") { + val id = 1L -@SpringBootTest -@Import(ReservationTimeService.class) -@Sql(scripts = "/truncate.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD) -class ReservationTimeServiceTest { + // Mocking the behavior of reservationTimeRepository.findByIdOrNull + every { reservationTimeRepository.findByIdOrNull(id) } returns null - @Autowired - private ReservationTimeService reservationTimeService; - @Autowired - private ReservationTimeRepository reservationTimeRepository; - @Autowired - private ReservationRepository reservationRepository; - @Autowired - private ThemeRepository themeRepository; - @Autowired - private MemberRepository memberRepository; + shouldThrow { + reservationTimeService.findTimeById(id) + }.apply { + errorType shouldBe ErrorType.RESERVATION_TIME_NOT_FOUND + httpStatus shouldBe HttpStatus.BAD_REQUEST + } + } + } - @Test - @DisplayName("중복된 예약 시간을 등록하는 경우 예외가 발생한다.") - void duplicateTimeFail() { - // given - reservationTimeRepository.save(new ReservationTimeEntity(null, LocalTime.of(12, 30))); + context("addTime") { + test("중복된 시간이 있으면 409 에러를 던진다.") { + val request = ReservationTimeRequest(startAt = LocalTime.of(10, 0)) - // when & then - assertThatThrownBy(() -> reservationTimeService.addTime(new ReservationTimeRequest(LocalTime.of(12, 30)))) - .isInstanceOf(RoomescapeException.class); - } + // Mocking the behavior of reservationTimeRepository.findByStartAt + every { reservationTimeRepository.findByStartAt(request.startAt) } returns listOf(mockk()) - @Test - @DisplayName("존재하지 않는 ID로 시간을 조회하면 예외가 발생한다.") - void findTimeByIdFail() { - // given - ReservationTimeEntity saved = reservationTimeRepository.save( - new ReservationTimeEntity(null, LocalTime.of(12, 30))); + shouldThrow { + reservationTimeService.addTime(request) + }.apply { + errorType shouldBe ErrorType.TIME_DUPLICATED + httpStatus shouldBe HttpStatus.CONFLICT + } + } + } - // when - assert saved.getId() != null; - long invalidTimeId = saved.getId() + 1; + context("removeTimeById") { + test("시간을 찾을 수 없으면 400 에러를 던진다.") { + val id = 1L - // when & then - assertThatThrownBy(() -> reservationTimeService.findTimeById(invalidTimeId)) - .isInstanceOf(RoomescapeException.class); - } + // Mocking the behavior of reservationTimeRepository.findByIdOrNull + every { reservationTimeRepository.findByIdOrNull(id) } returns null - @Test - @DisplayName("삭제하려는 시간에 예약이 존재하면 예외를 발생한다.") - void usingTimeDeleteFail() { - // given - LocalDateTime localDateTime = LocalDateTime.now().plusDays(1L).withNano(0); - ReservationTimeEntity reservationTime = reservationTimeRepository.save( - new ReservationTimeEntity(null, localDateTime.toLocalTime())); - ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "테마명", "설명", "썸네일URL")); - MemberEntity member = memberRepository.save( - new MemberEntity(null, "name", "email@email.com", "password", Role.MEMBER)); + shouldThrow { + reservationTimeService.removeTimeById(id) + }.apply { + errorType shouldBe ErrorType.RESERVATION_TIME_NOT_FOUND + httpStatus shouldBe HttpStatus.BAD_REQUEST + } + } - // when - reservationRepository.save( - new ReservationEntity(null, localDateTime.toLocalDate(), reservationTime, theme, member, - ReservationStatus.CONFIRMED)); + test("예약이 있는 시간이면 409 에러를 던진다.") { + val id = 1L + val reservationTime = ReservationTimeFixture.create() - // then - assert reservationTime.getId() != null; - assertThatThrownBy(() -> reservationTimeService.removeTimeById(reservationTime.getId())) - .isInstanceOf(RoomescapeException.class); - } -} + // Mocking the behavior of reservationTimeRepository.findByIdOrNull + every { reservationTimeRepository.findByIdOrNull(id) } returns reservationTime + + // Mocking the behavior of reservationRepository.findByReservationTime + every { reservationRepository.findByReservationTime(reservationTime) } returns listOf(mockk()) + + shouldThrow { + reservationTimeService.removeTimeById(id) + }.apply { + errorType shouldBe ErrorType.TIME_IS_USED_CONFLICT + httpStatus shouldBe HttpStatus.CONFLICT + } + } + } +})