Skip to content

Commit

Permalink
[Test/#145] UseCase 단위 테스트 구현 (#204)
Browse files Browse the repository at this point in the history
* test: BrowseProblemsUseCase 단위 테스트 추가

* test: CheckProblemUseCase 단위 테스트 추가

* test: ReadProblemUseCase 단위 테스트 추가

* test: SubscribeWorkbookUseCase 단위 테스트 추가

* test: 이미 구독중인 경우에 대한 단위 테스트 추가

* test: kotest를 활용한 단위테스트로 변경

* test: ReadArticleUseCase 단위 테스트 추가

* test: ReadWorkbookUseCase 단위 테스트 추가

* refactor: unit test code
  • Loading branch information
hun-ca authored Jul 16, 2024
1 parent 182f353 commit 1898531
Show file tree
Hide file tree
Showing 6 changed files with 448 additions and 0 deletions.
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(),
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

0 comments on commit 1898531

Please sign in to comment.