generated from pricelees/issue-pr-template
299 lines
10 KiB
Kotlin
299 lines
10 KiB
Kotlin
package roomescape.theme.web
|
|
|
|
import com.ninjasquad.springmockk.MockkBean
|
|
import com.ninjasquad.springmockk.SpykBean
|
|
import io.kotest.assertions.assertSoftly
|
|
import io.kotest.matchers.collections.shouldContainAll
|
|
import io.kotest.matchers.shouldBe
|
|
import io.mockk.every
|
|
import io.mockk.just
|
|
import io.mockk.runs
|
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
|
import org.springframework.http.MediaType
|
|
import org.springframework.test.web.servlet.MockMvc
|
|
import roomescape.auth.exception.AuthErrorCode
|
|
import roomescape.theme.business.ThemeService
|
|
import roomescape.theme.infrastructure.persistence.ThemeRepository
|
|
import roomescape.util.RoomescapeApiTest
|
|
import roomescape.util.ThemeFixture
|
|
|
|
@WebMvcTest(ThemeController::class)
|
|
class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|
|
|
@SpykBean
|
|
private lateinit var themeService: ThemeService
|
|
|
|
@MockkBean
|
|
private lateinit var themeRepository: ThemeRepository
|
|
|
|
init {
|
|
Given("모든 테마를 조회할 때") {
|
|
val endpoint = "/themes"
|
|
|
|
When("로그인 상태가 아니라면") {
|
|
doNotLogin()
|
|
|
|
Then("로그인 페이지로 이동한다.") {
|
|
runGetTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
) {
|
|
status { is3xxRedirection() }
|
|
header {
|
|
string("Location", "/login")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
When("로그인 상태라면") {
|
|
loginAsUser()
|
|
|
|
Then("조회에 성공한다.") {
|
|
every {
|
|
themeRepository.findAll()
|
|
} returns listOf(
|
|
ThemeFixture.create(id = 1, name = "theme1"),
|
|
ThemeFixture.create(id = 2, name = "theme2"),
|
|
ThemeFixture.create(id = 3, name = "theme3")
|
|
)
|
|
|
|
val response: ThemesResponse = runGetTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
) {
|
|
status { isOk() }
|
|
content {
|
|
contentType(MediaType.APPLICATION_JSON)
|
|
}
|
|
}.andReturn().readValue(ThemesResponse::class.java)
|
|
|
|
assertSoftly(response.themes) {
|
|
it.size shouldBe 3
|
|
it.map { m -> m.name } shouldContainAll listOf("theme1", "theme2", "theme3")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Given("테마를 추가할 때") {
|
|
val endpoint = "/themes"
|
|
val request = ThemeRequest(
|
|
name = "theme1",
|
|
description = "description1",
|
|
thumbnail = "http://example.com/thumbnail1.jpg"
|
|
)
|
|
|
|
When("로그인 상태가 아니라면") {
|
|
doNotLogin()
|
|
Then("로그인 페이지로 이동한다.") {
|
|
runPostTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
body = request,
|
|
) {
|
|
status { is3xxRedirection() }
|
|
header {
|
|
string("Location", "/login")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
When("관리자가 아닌 회원은") {
|
|
loginAsUser()
|
|
Then("로그인 페이지로 이동한다.") {
|
|
runPostTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
body = request,
|
|
) {
|
|
status { is3xxRedirection() }
|
|
jsonPath("$.code") { value(AuthErrorCode.ACCESS_DENIED.errorCode) }
|
|
}
|
|
}
|
|
}
|
|
|
|
When("동일한 이름의 테마가 있으면") {
|
|
loginAsAdmin()
|
|
|
|
Then("409 에러를 응답한다.") {
|
|
every {
|
|
themeRepository.existsByName(request.name)
|
|
} returns true
|
|
|
|
runPostTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
body = request,
|
|
) {
|
|
status { isConflict() }
|
|
jsonPath("$.errorType") { value("THEME_DUPLICATED") }
|
|
}
|
|
}
|
|
}
|
|
|
|
When("값이 잘못 입력되면 400 에러를 응답한다") {
|
|
beforeTest {
|
|
loginAsAdmin()
|
|
}
|
|
|
|
val request = ThemeRequest(
|
|
name = "theme1",
|
|
description = "description1",
|
|
thumbnail = "http://example.com/thumbnail1.jpg"
|
|
)
|
|
|
|
fun runTest(request: ThemeRequest) {
|
|
runPostTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
body = request,
|
|
) {
|
|
status { isBadRequest() }
|
|
}
|
|
}
|
|
|
|
Then("이름이 공백인 경우") {
|
|
val invalidRequest = request.copy(name = " ")
|
|
runTest(invalidRequest)
|
|
}
|
|
|
|
Then("이름이 20글자를 초과하는 경우") {
|
|
val invalidRequest = request.copy(name = "a".repeat(21))
|
|
runTest(invalidRequest)
|
|
}
|
|
|
|
Then("설명이 공백인 경우") {
|
|
val invalidRequest = request.copy(description = " ")
|
|
runTest(invalidRequest)
|
|
}
|
|
|
|
Then("설명이 100글자를 초과하는 경우") {
|
|
val invalidRequest = request.copy(description = "a".repeat(101))
|
|
runTest(invalidRequest)
|
|
}
|
|
|
|
Then("썸네일이 공백인 경우") {
|
|
val invalidRequest = request.copy(thumbnail = " ")
|
|
runTest(invalidRequest)
|
|
}
|
|
|
|
Then("썸네일이 URL 형식이 아닌 경우") {
|
|
val invalidRequest = request.copy(thumbnail = "invalid-url")
|
|
runTest(invalidRequest)
|
|
}
|
|
}
|
|
|
|
When("저장에 성공하면") {
|
|
loginAsAdmin()
|
|
|
|
val theme = ThemeFixture.create(
|
|
id = 1,
|
|
name = request.name,
|
|
description = request.description,
|
|
thumbnail = request.thumbnail
|
|
)
|
|
|
|
every {
|
|
themeService.createTheme(request)
|
|
} returns ThemeResponse(
|
|
id = theme.id!!,
|
|
name = theme.name,
|
|
description = theme.description,
|
|
thumbnail = theme.thumbnail
|
|
)
|
|
|
|
Then("201 응답을 받는다.") {
|
|
runPostTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
body = request,
|
|
) {
|
|
status { isCreated() }
|
|
header {
|
|
string("Location", "/themes/${theme.id}")
|
|
}
|
|
jsonPath("$.data.id") { value(theme.id) }
|
|
jsonPath("$.data.name") { value(theme.name) }
|
|
jsonPath("$.data.description") { value(theme.description) }
|
|
jsonPath("$.data.thumbnail") { value(theme.thumbnail) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Given("테마를 제거할 때") {
|
|
val themeId = 1L
|
|
val endpoint = "/themes/$themeId"
|
|
|
|
When("로그인 상태가 아니라면") {
|
|
doNotLogin()
|
|
Then("로그인 페이지로 이동한다.") {
|
|
runDeleteTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
) {
|
|
status { is3xxRedirection() }
|
|
header {
|
|
string("Location", "/login")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
When("관리자가 아닌 회원은") {
|
|
loginAsUser()
|
|
Then("로그인 페이지로 이동한다.") {
|
|
runDeleteTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
) {
|
|
status { is3xxRedirection() }
|
|
jsonPath("$.code") { value(AuthErrorCode.ACCESS_DENIED.errorCode) }
|
|
}
|
|
}
|
|
}
|
|
|
|
When("입력된 ID에 해당하는 테마가 없으면") {
|
|
loginAsAdmin()
|
|
|
|
Then("409 에러를 응답한다.") {
|
|
every {
|
|
themeRepository.isReservedTheme(themeId)
|
|
} returns true
|
|
|
|
runDeleteTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
) {
|
|
status { isConflict() }
|
|
jsonPath("$.errorType") { value("THEME_IS_USED_CONFLICT") }
|
|
}
|
|
}
|
|
}
|
|
|
|
When("정상적으로 제거되면") {
|
|
loginAsAdmin()
|
|
|
|
every {
|
|
themeRepository.isReservedTheme(themeId)
|
|
} returns false
|
|
|
|
every {
|
|
themeRepository.deleteById(themeId)
|
|
} just runs
|
|
|
|
Then("204 응답을 받는다.") {
|
|
runDeleteTest(
|
|
mockMvc = mockMvc,
|
|
endpoint = endpoint,
|
|
) {
|
|
status { isNoContent() }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|