Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Test/#145] UseCase 단위 테스트 구현 #204

Merged
merged 11 commits into from
Jul 16, 2024
Original file line number Diff line number Diff line change
@@ -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<ArticleDao>()
readArticleWriterRecordService = mockk<ReadArticleWriterRecordService>()
browseArticleProblemsService = mockk<BrowseArticleProblemsService>()
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(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 Category 이넘을 사용해서 하는게 좋을꺼 같아요!

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<Exception> { useCase.execute(useCaseIn) }

verify(exactly = 1) { articleDao.selectArticleRecord(any()) }
}
}
}
})
Original file line number Diff line number Diff line change
@@ -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<ProblemDao>()
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<Exception> { useCase.execute(useCaseIn) }

verify(exactly = 1) { problemDao.selectProblemsByArticleId(any()) }
}
}
}
})
Original file line number Diff line number Diff line change
@@ -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<ProblemDao>()
submitHistoryDao = mockk<SubmitHistoryDao>()
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<Exception> { useCase.execute(useCaseIn) }
verify(exactly = 1) { problemDao.selectProblemAnswer(any()) }
}
}
}
})
Original file line number Diff line number Diff line change
@@ -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<ProblemDao>()
contentsJsonMapper = mockk<ContentsJsonMapper>()
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<Exception> { useCase.execute(useCaseIn) }

verify(exactly = 1) { problemDao.selectProblemContents(any()) }
}
}
}
})
Original file line number Diff line number Diff line change
@@ -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 = "[email protected]")

beforeContainer {
subscriptionDao = mockk<SubscriptionDao>()
memberService = mockk<MemberService>()
applicationEventPublisher = mockk<ApplicationEventPublisher>()
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<Exception> { 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) }
}
}
}
})
Loading
Loading