package roomescape.theme.business import io.kotest.assertions.assertSoftly 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.theme.infrastructure.persistence.ThemeEntity import roomescape.theme.infrastructure.persistence.ThemeRepository import roomescape.theme.web.ThemeRequest import roomescape.util.ThemeFixture class ThemeServiceTest : FunSpec({ val themeRepository: ThemeRepository = mockk() val themeService = ThemeService(themeRepository) context("findThemeById") { val themeId = 1L test("조회 성공") { val theme: ThemeEntity = ThemeFixture.create(id = themeId) every { themeRepository.findByIdOrNull(themeId) } returns theme theme.id shouldBe themeId } test("ID로 테마를 찾을 수 없으면 400 예외를 던진다.") { every { themeRepository.findByIdOrNull(themeId) } returns null val exception = shouldThrow { themeService.findById(themeId) } exception.errorType shouldBe ErrorType.THEME_NOT_FOUND } } context("findAllThemes") { test("모든 테마를 조회한다.") { val themes = listOf(ThemeFixture.create(id = 1, name = "t1"), ThemeFixture.create(id = 2, name = "t2")) every { themeRepository.findAll() } returns themes assertSoftly(themeService.findAll()) { this.themes.size shouldBe themes.size this.themes[0].name shouldBe "t1" this.themes[1].name shouldBe "t2" } } } context("save") { test("테마 이름이 중복되면 409 예외를 던진다.") { val name = "Duplicate Theme" every { themeRepository.existsByName(name) } returns true val exception = shouldThrow { themeService.create(ThemeRequest( name = name, description = "Description", thumbnail = "http://example.com/thumbnail.jpg" )) } assertSoftly(exception) { this.errorType shouldBe ErrorType.THEME_DUPLICATED this.httpStatus shouldBe HttpStatus.CONFLICT } } } context("deleteById") { test("이미 예약 중인 테마라면 409 예외를 던진다.") { val themeId = 1L every { themeRepository.isReservedTheme(themeId) } returns true val exception = shouldThrow { themeService.deleteById(themeId) } assertSoftly(exception) { this.errorType shouldBe ErrorType.THEME_IS_USED_CONFLICT this.httpStatus shouldBe HttpStatus.CONFLICT } } } })