diff --git a/api/src/test/kotlin/com/few/api/domain/article/usecase/ReadArticleUseCaseTest.kt b/api/src/test/kotlin/com/few/api/domain/article/usecase/ReadArticleUseCaseTest.kt new file mode 100644 index 000000000..914fa4812 --- /dev/null +++ b/api/src/test/kotlin/com/few/api/domain/article/usecase/ReadArticleUseCaseTest.kt @@ -0,0 +1,75 @@ +package com.few.api.domain.article.usecase + +import com.few.api.domain.article.service.BrowseArticleProblemsService +import com.few.api.domain.article.service.ReadArticleWriterRecordService +import com.few.api.domain.article.service.dto.BrowseArticleProblemsOutDto +import com.few.api.domain.article.service.dto.ReadWriterOutDto +import com.few.api.domain.article.usecase.dto.ReadArticleUseCaseIn +import com.few.api.repo.dao.article.ArticleDao +import com.few.api.repo.dao.article.record.SelectArticleRecord +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.BehaviorSpec +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify + +import java.net.URL +import java.time.LocalDateTime + +class ReadArticleUseCaseTest : BehaviorSpec({ + + lateinit var articleDao: ArticleDao + lateinit var readArticleWriterRecordService: ReadArticleWriterRecordService + lateinit var browseArticleProblemsService: BrowseArticleProblemsService + lateinit var useCase: ReadArticleUseCase + val useCaseIn = ReadArticleUseCaseIn(articleId = 1L) + + beforeContainer { + articleDao = mockk() + readArticleWriterRecordService = mockk() + browseArticleProblemsService = mockk() + useCase = ReadArticleUseCase(articleDao, readArticleWriterRecordService, browseArticleProblemsService) + } + + given("아티클 조회 요청이 온 상황에서") { + `when`("아티클과 작가가 존재할 경우") { + val record = SelectArticleRecord( + articleId = 1L, + writerId = 1L, + mainImageURL = URL("https://jh-labs.tistory.com/"), + title = "title", + category = (10).toByte(), + content = "content", + createdAt = LocalDateTime.now() + ) + val writerSvcOutDto = ReadWriterOutDto( + writerId = 1L, + name = "hunca", + url = URL("https://jh-labs.tistory.com/") + ) + val probSvcOutDto = BrowseArticleProblemsOutDto(problemIds = listOf(1, 2, 3)) + + every { articleDao.selectArticleRecord(any()) } returns record + every { readArticleWriterRecordService.execute(any()) } returns writerSvcOutDto + every { browseArticleProblemsService.execute(any()) } returns probSvcOutDto + + then("아티클이 정상 조회된다") { + useCase.execute(useCaseIn) + + verify(exactly = 1) { articleDao.selectArticleRecord(any()) } + verify(exactly = 1) { readArticleWriterRecordService.execute(any()) } + verify(exactly = 1) { browseArticleProblemsService.execute(any()) } + } + } + + `when`("존재하지 않는 아티클일 경우") { + every { articleDao.selectArticleRecord(any()) } returns null + + then("예외가 발생한다") { + shouldThrow { useCase.execute(useCaseIn) } + + verify(exactly = 1) { articleDao.selectArticleRecord(any()) } + } + } + } +}) \ No newline at end of file diff --git a/api/src/test/kotlin/com/few/api/domain/problem/usecase/BrowseProblemsUseCaseTest.kt b/api/src/test/kotlin/com/few/api/domain/problem/usecase/BrowseProblemsUseCaseTest.kt new file mode 100644 index 000000000..ca54ea69e --- /dev/null +++ b/api/src/test/kotlin/com/few/api/domain/problem/usecase/BrowseProblemsUseCaseTest.kt @@ -0,0 +1,45 @@ +package com.few.api.domain.problem.usecase + +import com.few.api.domain.problem.usecase.dto.BrowseProblemsUseCaseIn +import com.few.api.repo.dao.problem.ProblemDao +import com.few.api.repo.dao.problem.record.ProblemIdsRecord +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.BehaviorSpec +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify + +class BrowseProblemsUseCaseTest : BehaviorSpec({ + + lateinit var problemDao: ProblemDao + lateinit var useCase: BrowseProblemsUseCase + val useCaseIn = BrowseProblemsUseCaseIn(articleId = 1L) + + beforeContainer { + problemDao = mockk() + useCase = BrowseProblemsUseCase(problemDao) + } + + given("특정 아티클에 대한") { + `when`("문제가 존재할 경우") { + val problemIdsRecord = ProblemIdsRecord(listOf(1, 2, 3)) + every { problemDao.selectProblemsByArticleId(any()) } returns problemIdsRecord + + then("문제번호가 정상적으로 조회된다") { + useCase.execute(useCaseIn) + + verify(exactly = 1) { problemDao.selectProblemsByArticleId(any()) } + } + } + + `when`("문제가 존재하지 않을 경우") { + every { problemDao.selectProblemsByArticleId(any()) } returns null + + then("예외가 발생한다") { + shouldThrow { useCase.execute(useCaseIn) } + + verify(exactly = 1) { problemDao.selectProblemsByArticleId(any()) } + } + } + } +}) \ No newline at end of file diff --git a/api/src/test/kotlin/com/few/api/domain/problem/usecase/CheckProblemUseCaseTest.kt b/api/src/test/kotlin/com/few/api/domain/problem/usecase/CheckProblemUseCaseTest.kt new file mode 100644 index 000000000..5bdd418b4 --- /dev/null +++ b/api/src/test/kotlin/com/few/api/domain/problem/usecase/CheckProblemUseCaseTest.kt @@ -0,0 +1,74 @@ +package com.few.api.domain.problem.usecase + +import com.few.api.domain.problem.usecase.dto.CheckProblemUseCaseIn +import com.few.api.repo.dao.problem.ProblemDao +import com.few.api.repo.dao.problem.SubmitHistoryDao +import com.few.api.repo.dao.problem.record.SelectProblemAnswerRecord +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify + +class CheckProblemUseCaseTest : BehaviorSpec({ + + lateinit var problemDao: ProblemDao + lateinit var submitHistoryDao: SubmitHistoryDao + lateinit var useCase: CheckProblemUseCase + + beforeContainer { + problemDao = mockk() + submitHistoryDao = mockk() + useCase = CheckProblemUseCase(problemDao, submitHistoryDao) + } + + given("문제 정답 확인 요청이 온 상황에서") { + `when`("제출 값과 문제 정답이 같을 경우") { + val submissionVal = "1" + val answer = submissionVal + val useCaseIn = CheckProblemUseCaseIn(problemId = 1L, sub = submissionVal) + val answerRecord = SelectProblemAnswerRecord(id = 1L, answer = answer, explanation = "해설입니다.") + + every { problemDao.selectProblemAnswer(any()) } returns answerRecord + every { submitHistoryDao.insertSubmitHistory(any()) } returns 1L + + then("문제가 정답처리 된다") { + val useCaseOut = useCase.execute(useCaseIn) + + useCaseOut.isSolved shouldBe true + verify(exactly = 1) { problemDao.selectProblemAnswer(any()) } + verify(exactly = 1) { submitHistoryDao.insertSubmitHistory(any()) } + } + } + + `when`("제출 값과 문제 정답이 다를 경우") { + val submissionVal = "1" + val answer = "2" + val useCaseIn = CheckProblemUseCaseIn(problemId = 1L, sub = submissionVal) + val answerRecord = SelectProblemAnswerRecord(id = 1L, answer = answer, explanation = "해설입니다.") + + every { problemDao.selectProblemAnswer(any()) } returns answerRecord + every { submitHistoryDao.insertSubmitHistory(any()) } returns 1L + + then("문제가 오답처리 된다") { + val useCaseOut = useCase.execute(useCaseIn) + + useCaseOut.isSolved shouldBe false + verify(exactly = 1) { problemDao.selectProblemAnswer(any()) } + verify(exactly = 1) { submitHistoryDao.insertSubmitHistory(any()) } + } + } + + `when`("존재하지 않는 문제일 경우") { + val useCaseIn = CheckProblemUseCaseIn(problemId = 1L, sub = "1") + + every { problemDao.selectProblemAnswer(any()) } returns null + + then("예외가 발생한다") { + shouldThrow { useCase.execute(useCaseIn) } + verify(exactly = 1) { problemDao.selectProblemAnswer(any()) } + } + } + } +}) \ No newline at end of file diff --git a/api/src/test/kotlin/com/few/api/domain/problem/usecase/ReadProblemUseCaseTest.kt b/api/src/test/kotlin/com/few/api/domain/problem/usecase/ReadProblemUseCaseTest.kt new file mode 100644 index 000000000..d97f6490c --- /dev/null +++ b/api/src/test/kotlin/com/few/api/domain/problem/usecase/ReadProblemUseCaseTest.kt @@ -0,0 +1,59 @@ +package com.few.api.domain.problem.usecase + +import com.few.api.domain.problem.usecase.dto.ReadProblemUseCaseIn +import com.few.api.repo.dao.problem.ProblemDao +import com.few.api.repo.dao.problem.record.SelectProblemRecord +import com.few.api.repo.dao.problem.support.Content +import com.few.api.repo.dao.problem.support.Contents +import com.few.api.repo.dao.problem.support.ContentsJsonMapper +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.BehaviorSpec +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify + +class ReadProblemUseCaseTest : BehaviorSpec({ + + lateinit var problemDao: ProblemDao + lateinit var contentsJsonMapper: ContentsJsonMapper + lateinit var useCase: ReadProblemUseCase + val useCaseIn = ReadProblemUseCaseIn(problemId = 1L) + + beforeContainer { + problemDao = mockk() + contentsJsonMapper = mockk() + useCase = ReadProblemUseCase(problemDao, contentsJsonMapper) + } + + given("문제를 조회할 상황에서") { + `when`("문제가 존재할 경우") { + val problemRecord = SelectProblemRecord(id = 1L, title = "title", contents = "{}") + val contents = Contents( + listOf( + Content(number = 1, content = "{}"), + Content(number = 2, content = "{}") + ) + ) + + every { problemDao.selectProblemContents(any()) } returns problemRecord + every { contentsJsonMapper.toObject(any()) } returns contents + + then("정상적으로 실행되어야 한다") { + useCase.execute(useCaseIn) + + verify(exactly = 1) { problemDao.selectProblemContents(any()) } + verify(exactly = 1) { contentsJsonMapper.toObject(any()) } + } + } + + `when`("문제가 존재하지 않을 경우") { + every { problemDao.selectProblemContents(any()) } returns null + + then("예외가 발생해야 한다") { + shouldThrow { useCase.execute(useCaseIn) } + + verify(exactly = 1) { problemDao.selectProblemContents(any()) } + } + } + } +}) \ No newline at end of file diff --git a/api/src/test/kotlin/com/few/api/domain/subscription/usecase/SubscribeWorkbookUseCaseTest.kt b/api/src/test/kotlin/com/few/api/domain/subscription/usecase/SubscribeWorkbookUseCaseTest.kt new file mode 100644 index 000000000..cb781f828 --- /dev/null +++ b/api/src/test/kotlin/com/few/api/domain/subscription/usecase/SubscribeWorkbookUseCaseTest.kt @@ -0,0 +1,112 @@ +package com.few.api.domain.subscription.usecase + +import com.few.api.domain.subscription.event.dto.WorkbookSubscriptionEvent +import com.few.api.domain.subscription.service.MemberService +import com.few.api.domain.subscription.service.dto.MemberIdOutDto +import com.few.api.domain.subscription.usecase.dto.SubscribeWorkbookUseCaseIn +import com.few.api.repo.dao.subscription.SubscriptionDao +import com.few.api.repo.dao.subscription.record.WorkbookSubscriptionStatus +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.BehaviorSpec +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import io.mockk.just +import io.mockk.Runs +import org.springframework.context.ApplicationEventPublisher + +class SubscribeWorkbookUseCaseTest : BehaviorSpec({ + + lateinit var subscriptionDao: SubscriptionDao + lateinit var memberService: MemberService + lateinit var applicationEventPublisher: ApplicationEventPublisher + lateinit var useCase: SubscribeWorkbookUseCase + val workbookId = 1L + val useCaseIn = SubscribeWorkbookUseCaseIn(workbookId = workbookId, email = "test@test.com") + + beforeContainer { + subscriptionDao = mockk() + memberService = mockk() + applicationEventPublisher = mockk() + useCase = SubscribeWorkbookUseCase(subscriptionDao, memberService, applicationEventPublisher) + } + + given("구독 요청이 온 상황에서") { + `when`("subscriptionStatus가 null일 경우") { + val serviceOutDto = MemberIdOutDto(memberId = 1L) + val event = WorkbookSubscriptionEvent(workbookId) + + every { memberService.readMemberId(any()) } returns null + every { memberService.insertMember(any()) } returns serviceOutDto + every { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) } returns null + every { subscriptionDao.insertWorkbookSubscription(any()) } just Runs + every { applicationEventPublisher.publishEvent(event) } answers { + println("Mocking applicationEventPublisher.publishEvent(any()) was called") + } + + then("신규 구독을 추가한다") { + useCase.execute(useCaseIn) + + verify(exactly = 1) { memberService.insertMember(any()) } + verify(exactly = 1) { subscriptionDao.insertWorkbookSubscription(any()) } + verify(exactly = 0) { subscriptionDao.countWorkbookMappedArticles(any()) } + verify(exactly = 0) { subscriptionDao.reSubscribeWorkbookSubscription(any()) } + verify(exactly = 1) { applicationEventPublisher.publishEvent(event) } + } + } + + `when`("구독을 취소한 경우") { + val day = 2 + val lastDay = 3 + val serviceOutDto = MemberIdOutDto(memberId = 1L) + val subscriptionStatusRecord = WorkbookSubscriptionStatus(workbookId = workbookId, isActiveSub = false, day) + val event = WorkbookSubscriptionEvent(workbookId) + + every { memberService.readMemberId(any()) } returns null + every { memberService.insertMember(any()) } returns serviceOutDto + every { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) } returns subscriptionStatusRecord + every { subscriptionDao.countWorkbookMappedArticles(any()) } returns lastDay + every { subscriptionDao.reSubscribeWorkbookSubscription(any()) } just Runs + every { applicationEventPublisher.publishEvent(event) } answers { + println("Mocking applicationEventPublisher.publishEvent(any()) was called") + } + + then("재구독한다") { + useCase.execute(useCaseIn) + + verify(exactly = 1) { memberService.insertMember(any()) } + verify(exactly = 0) { subscriptionDao.insertWorkbookSubscription(any()) } + verify(exactly = 1) { subscriptionDao.countWorkbookMappedArticles(any()) } + verify(exactly = 1) { subscriptionDao.reSubscribeWorkbookSubscription(any()) } + verify(exactly = 1) { applicationEventPublisher.publishEvent(event) } + } + } + + `when`("이미 구독하고 있을 경우") { + val day = 2 + val lastDay = 3 + val serviceOutDto = MemberIdOutDto(memberId = 1L) + val subscriptionStatusRecord = WorkbookSubscriptionStatus(workbookId = workbookId, isActiveSub = true, day) + val event = WorkbookSubscriptionEvent(workbookId) + + every { memberService.readMemberId(any()) } returns null + every { memberService.insertMember(any()) } returns serviceOutDto + every { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) } returns subscriptionStatusRecord + every { subscriptionDao.countWorkbookMappedArticles(any()) } returns lastDay + every { subscriptionDao.reSubscribeWorkbookSubscription(any()) } just Runs + every { applicationEventPublisher.publishEvent(event) } answers { + println("Mocking applicationEventPublisher.publishEvent(any()) was called") + } + + then("예외가 발생한다") { + shouldThrow { useCase.execute(useCaseIn) } + + verify(exactly = 1) { memberService.insertMember(any()) } + verify(exactly = 0) { subscriptionDao.insertWorkbookSubscription(any()) } + verify(exactly = 0) { subscriptionDao.countWorkbookMappedArticles(any()) } + verify(exactly = 0) { subscriptionDao.reSubscribeWorkbookSubscription(any()) } + verify(exactly = 0) { applicationEventPublisher.publishEvent(event) } + } + } + } +}) \ No newline at end of file diff --git a/api/src/test/kotlin/com/few/api/domain/workbook/usecase/ReadWorkbookUseCaseTest.kt b/api/src/test/kotlin/com/few/api/domain/workbook/usecase/ReadWorkbookUseCaseTest.kt new file mode 100644 index 000000000..2099903d2 --- /dev/null +++ b/api/src/test/kotlin/com/few/api/domain/workbook/usecase/ReadWorkbookUseCaseTest.kt @@ -0,0 +1,83 @@ +package com.few.api.domain.workbook.usecase + +import com.few.api.domain.workbook.service.WorkbookArticleService +import com.few.api.domain.workbook.service.WorkbookMemberService +import com.few.api.domain.workbook.service.dto.WorkBookArticleOutDto +import com.few.api.domain.workbook.service.dto.WriterOutDto +import com.few.api.domain.workbook.usecase.dto.ReadWorkbookUseCaseIn +import com.few.api.repo.dao.workbook.WorkbookDao +import com.few.api.repo.dao.workbook.record.SelectWorkBookRecord +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.BehaviorSpec +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify + +import java.net.URL +import java.time.LocalDateTime + +class ReadWorkbookUseCaseTest : BehaviorSpec({ + lateinit var workbookDao: WorkbookDao + lateinit var workbookArticleService: WorkbookArticleService + lateinit var workbookMemberService: WorkbookMemberService + lateinit var useCase: ReadWorkbookUseCase + val useCaseIn = ReadWorkbookUseCaseIn(workbookId = 1L) + + beforeContainer { + workbookDao = mockk() + workbookArticleService = mockk() + workbookMemberService = mockk() + useCase = ReadWorkbookUseCase(workbookDao, workbookArticleService, workbookMemberService) + } + + given("워크북 조회 요청이 온 상황에서") { + `when`("워크북과 작가가 존재할 경우") { + every { workbookDao.selectWorkBook(any()) } returns SelectWorkBookRecord( + id = 1L, + title = "workbook title", + mainImageUrl = URL("https://jh-labs.tistory.com/"), + category = (10).toByte(), + description = "workbook description", + createdAt = LocalDateTime.now() + ) + every { workbookArticleService.browseWorkbookArticles(any()) } returns listOf( + WorkBookArticleOutDto( + articleId = 1L, + writerId = 1L, + mainImageURL = URL("https://jh-labs.tistory.com/"), + title = "article title", + category = (10).toByte(), + content = "article description", + createdAt = LocalDateTime.now() + ) + ) + every { workbookMemberService.browseWriterRecords(any()) } returns listOf( + WriterOutDto( + writerId = 1L, + name = "hunca", + url = URL("https://jh-labs.tistory.com/") + ) + ) + + then("워크북 정상 조회된다") { + useCase.execute(useCaseIn) + + verify(exactly = 1) { workbookDao.selectWorkBook(any()) } + verify(exactly = 1) { workbookArticleService.browseWorkbookArticles(any()) } + verify(exactly = 1) { workbookMemberService.browseWriterRecords(any()) } + } + } + + `when`("워크북이 존재하지 않을 경우") { + every { workbookDao.selectWorkBook(any()) } returns null + + then("예외가 발생한다") { + shouldThrow { useCase.execute(useCaseIn) } + + verify(exactly = 1) { workbookDao.selectWorkBook(any()) } + verify(exactly = 0) { workbookArticleService.browseWorkbookArticles(any()) } + verify(exactly = 0) { workbookMemberService.browseWriterRecords(any()) } + } + } + } +}) \ No newline at end of file