generated from pricelees/issue-pr-template
307 lines
11 KiB
Kotlin
307 lines
11 KiB
Kotlin
package roomescape.reservation.web
|
|
|
|
import com.ninjasquad.springmockk.MockkBean
|
|
import com.ninjasquad.springmockk.SpykBean
|
|
import io.kotest.assertions.assertSoftly
|
|
import io.kotest.matchers.collections.shouldHaveSize
|
|
import io.kotest.matchers.shouldBe
|
|
import io.mockk.every
|
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
|
import org.springframework.context.annotation.Import
|
|
import org.springframework.data.repository.findByIdOrNull
|
|
import org.springframework.http.MediaType
|
|
import org.springframework.test.web.servlet.MockMvc
|
|
import roomescape.common.config.JacksonConfig
|
|
import roomescape.common.exception.ErrorType
|
|
import roomescape.reservation.business.TimeService
|
|
import roomescape.reservation.infrastructure.persistence.ReservationRepository
|
|
import roomescape.reservation.infrastructure.persistence.TimeEntity
|
|
import roomescape.reservation.infrastructure.persistence.TimeRepository
|
|
import roomescape.util.ReservationFixture
|
|
import roomescape.util.RoomescapeApiTest
|
|
import roomescape.util.ThemeFixture
|
|
import roomescape.util.TimeFixture
|
|
import java.time.LocalDate
|
|
import java.time.LocalTime
|
|
|
|
@WebMvcTest(TimeController::class)
|
|
@Import(JacksonConfig::class)
|
|
class TimeControllerTest(
|
|
val mockMvc: MockMvc,
|
|
) : RoomescapeApiTest() {
|
|
|
|
@SpykBean
|
|
private lateinit var timeService: TimeService
|
|
|
|
@MockkBean
|
|
private lateinit var timeRepository: TimeRepository
|
|
|
|
@MockkBean
|
|
private lateinit var reservationRepository: ReservationRepository
|
|
|
|
init {
|
|
Given("등록된 모든 시간을 조회할 때") {
|
|
val endpoint = "/times"
|
|
|
|
When("관리자인 경우") {
|
|
beforeTest {
|
|
loginAsAdmin()
|
|
}
|
|
|
|
Then("정상 응답") {
|
|
every {
|
|
timeRepository.findAll()
|
|
} returns listOf(
|
|
TimeFixture.create(id = 1L),
|
|
TimeFixture.create(id = 2L)
|
|
)
|
|
|
|
runGetTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
log = true
|
|
) {
|
|
status { isOk() }
|
|
content {
|
|
contentType(MediaType.APPLICATION_JSON)
|
|
jsonPath("$.data.times[0].id") { value(1) }
|
|
jsonPath("$.data.times[1].id") { value(2) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
When("관리자가 아닌 경우") {
|
|
loginAsUser()
|
|
|
|
Then("로그인 페이지로 이동") {
|
|
runGetTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
log = true
|
|
) {
|
|
status { is3xxRedirection() }
|
|
header { string("Location", "/login") }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Given("시간을 추가할 때") {
|
|
val endpoint = "/times"
|
|
|
|
When("관리자인 경우") {
|
|
beforeTest {
|
|
loginAsAdmin()
|
|
}
|
|
val time = LocalTime.of(10, 0)
|
|
val request = TimeCreateRequest(startAt = time)
|
|
|
|
Then("시간 형식이 HH:mm이 아니거나, 범위를 벗어나면 400 응답") {
|
|
listOf(
|
|
"{\"startAt\": \"23:30:30\"}",
|
|
"{\"startAt\": \"24:59\"}",
|
|
).forEach {
|
|
runPostTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
body = it,
|
|
log = true
|
|
) {
|
|
status { isBadRequest() }
|
|
}
|
|
}
|
|
}
|
|
|
|
Then("정상 응답") {
|
|
every {
|
|
timeService.create(request)
|
|
} returns TimeCreateResponse(id = 1, startAt = time)
|
|
|
|
runPostTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
body = request,
|
|
log = true
|
|
) {
|
|
status { isCreated() }
|
|
content {
|
|
contentType(MediaType.APPLICATION_JSON)
|
|
jsonPath("$.data.id") { value(1) }
|
|
jsonPath("$.data.startAt") { value("10:00") }
|
|
}
|
|
}
|
|
}
|
|
|
|
Then("동일한 시간이 존재하면 409 응답") {
|
|
every {
|
|
timeRepository.existsByStartAt(time)
|
|
} returns true
|
|
|
|
runPostTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
body = request,
|
|
log = true
|
|
) {
|
|
status { isConflict() }
|
|
content {
|
|
contentType(MediaType.APPLICATION_JSON)
|
|
jsonPath("$.errorType") { value(ErrorType.TIME_DUPLICATED.name) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
When("관리자가 아닌 경우") {
|
|
loginAsUser()
|
|
|
|
Then("로그인 페이지로 이동") {
|
|
runPostTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
body = TimeFixture.create(),
|
|
log = true
|
|
) {
|
|
status { is3xxRedirection() }
|
|
header { string("Location", "/login") }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Given("시간을 삭제할 때") {
|
|
val endpoint = "/times/1"
|
|
|
|
When("관리자인 경우") {
|
|
beforeTest {
|
|
loginAsAdmin()
|
|
}
|
|
|
|
Then("정상 응답") {
|
|
every {
|
|
timeService.deleteById(1L)
|
|
} returns Unit
|
|
|
|
runDeleteTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
log = true
|
|
) {
|
|
status { isNoContent() }
|
|
}
|
|
}
|
|
|
|
Then("없는 시간을 조회하면 400 응답") {
|
|
val id = 1L
|
|
every {
|
|
timeRepository.findByIdOrNull(id)
|
|
} returns null
|
|
|
|
runDeleteTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = "/times/$id",
|
|
log = true
|
|
) {
|
|
status { isBadRequest() }
|
|
content {
|
|
contentType(MediaType.APPLICATION_JSON)
|
|
jsonPath("$.errorType") { value(ErrorType.TIME_NOT_FOUND.name) }
|
|
}
|
|
}
|
|
}
|
|
|
|
Then("예약이 있는 시간을 삭제하면 409 응답") {
|
|
val id = 1L
|
|
every {
|
|
timeRepository.findByIdOrNull(id)
|
|
} returns TimeFixture.create(id = id)
|
|
|
|
every {
|
|
reservationRepository.findByTime(any())
|
|
} returns listOf(ReservationFixture.create())
|
|
|
|
runDeleteTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = "/times/$id",
|
|
log = true
|
|
) {
|
|
status { isConflict() }
|
|
content {
|
|
contentType(MediaType.APPLICATION_JSON)
|
|
jsonPath("$.errorType") { value(ErrorType.TIME_IS_USED_CONFLICT.name) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
When("관리자가 아닌 경우") {
|
|
loginAsUser()
|
|
|
|
Then("로그인 페이지로 이동") {
|
|
runDeleteTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
log = true
|
|
) {
|
|
status { is3xxRedirection() }
|
|
header { string("Location", "/login") }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Given("날짜, 테마가 주어졌을 때") {
|
|
loginAsUser()
|
|
|
|
val date: LocalDate = LocalDate.now()
|
|
val themeId = 1L
|
|
|
|
When("저장된 예약 시간이 있으면") {
|
|
val times: List<TimeEntity> = listOf(
|
|
TimeFixture.create(id = 1L, startAt = LocalTime.of(10, 0)),
|
|
TimeFixture.create(id = 2L, startAt = LocalTime.of(11, 0))
|
|
)
|
|
|
|
every {
|
|
timeRepository.findAll()
|
|
} returns times
|
|
|
|
Then("그 시간과, 해당 날짜와 테마에 대한 예약 여부가 담긴 목록을 응답") {
|
|
|
|
every {
|
|
reservationRepository.findByDateAndThemeId(date, themeId)
|
|
} returns listOf(
|
|
ReservationFixture.create(
|
|
id = 1L,
|
|
date = date,
|
|
theme = ThemeFixture.create(id = themeId),
|
|
time = times[0]
|
|
)
|
|
)
|
|
|
|
val response = runGetTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = "/times/filter?date=$date&themeId=$themeId",
|
|
log = true
|
|
) {
|
|
status { isOk() }
|
|
content {
|
|
contentType(MediaType.APPLICATION_JSON)
|
|
}
|
|
}.andReturn().readValue(TimeWithAvailabilityListResponse::class.java)
|
|
|
|
assertSoftly(response.times) {
|
|
this shouldHaveSize times.size
|
|
this[0].id shouldBe times[0].id
|
|
this[0].isAvailable shouldBe false
|
|
|
|
this[1].id shouldBe times[1].id
|
|
this[1].isAvailable shouldBe true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|