๐<์ฝํ๋ฆฐ ์ฝ๋ฃจํด์ ์ ์> ์ฑ ์ ๊ฐ์ฅ ๋ง์ง๋ง ์ฅ์ธ 12์ฅ์์๋ "์ฝ๋ฃจํด ๋จ์ ํ ์คํธ"์ ๋ํด ๋ค๋ฃฌ๋ค.
์ด๋ ํ ์คํธ ๋๋ธ์ ๋ํด ์ค๋ช ํด์ฃผ๋ฉด์ ๊ทธ ์ข ๋ฅ ์ค ํ๋์ธ Stub์ ๋ค์ด์ฃผ์๋ค. ๊ทธ๋ฌ๋ ์ฑ ์ ์ฝ๋ ๋น์์ ๋๋ ํ ์คํธ ์ฝ๋๋ฅผ ์ฒ์ ์ ํ๊ธฐ์ Stub์ ์ ์ฌ์ฉํ๋์ง ์ดํด๊ฐ ๋์ง ์์๋ค.
๊ทธ๋ฌ๋ค, KMP ํ๋ก์ ํธ์์ kotest๋ฅผ ์ด์ฉํด ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ๊ธฐํ๊ฐ ์์๋๋ฐ ๊ธฐ์กด์ ์ฌ์ฉํ Mockk ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ฉํฐํ๋ซํผ์์ ์ฌ์ฉ์ด ๋ถ๊ฐํ๊ธฐ์ Stub์ผ๋ก ๊ตฌํํด์ผ๋ง ํ์๋ค. ์ด ๊ณผ์ ๋๋ถ์ Stub์ด ๋ฌด์์ธ์ง ์ดํด๊ฐ ๋์๊ณ ๊ทธ ๊ณผ์ ์ ์ค๋ช ํด๋ณด๋ ค ํ๋ค.
ํ ์คํธ ๋๋ธ
์ฐ์ ํ ์คํธ ๋๋ธ์ ๋ํด ๋จผ์ ์์๋ณด์.
ํ ์คํธ ๋๋ธ์ด๋, ๋ค๋ฅธ ๊ฐ์ฒด์ ์์กด์ฑ์ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ํ ์คํธํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก "๊ฐ์ฒด์ ๋ํ ๋์ฒด๋ฌผ"์ ์๋ฏธํ๋ค.
์ ๊ทธ๋ฆผ์ฒ๋ผ "๊ฐ์ฒด"๋ฅผ ํ ์คํธ ํ๊ณ ์ถ์๋ฐ ์ด "๊ฐ์ฒด"๊ฐ "๋ค๋ฅธ ๊ฐ์ฒด"์ ์์กด์ฑ์ด ์๋ค๋ฉด ๊ทธ "๋ค๋ฅธ ๊ฐ์ฒด"์ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ๋ ์์ฑํด ์ค์ผ ํ๋ค๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด์ฃผ๋ ๊ฒ์ด ๋ฐ๋ก "ํ ์คํธ ๋๋ธ"์ธ ๊ฒ์ด๋ค.
๋ด๊ฐ ์ ์ฉํ๋ "๋๋ก์ด๋๋์ด์ธ "์ ์ฝ๋๋ฅผ ์์๋ก ๋ค์ด๋ณด๊ฒ ๋ค.
@Factory
class GetSponsorsUseCase(
private val sponsorRepository: SponsorRepository,
) {
suspend operator fun invoke(): List<Sponsor> =
sponsorRepository
.getSponsors()
.sortedBy { it.grade.priority }
}
interface SponsorRepository {
suspend fun getSponsors(): List<Sponsor>
}
ํ์๋ GetSponsorsUseCase์ ๋ํ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์ถ์๋ค.
๊ทธ๋ฌ๋ GetSponsorsUseCase๋ SponsorRepository์ ์์กด์ฑ์ด ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ด ๋๋ฌธ์ GetSponsorsUseCase๋ฅผ ํ ์คํธํ๊ธฐ ์ํด์๋ SponsorRepository์ ๋ํ ๊ตฌํ์ฒด๊ฐ ์์ด์ผ ํ๋ ๊ฒ์ด๋ค.
Stub
๊ทธ๋ ๋ค๋ฉด ์ด์ Stub์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด ๋ณด์.
Stub ๊ฐ์ฒด๋, ๋ฏธ๋ฆฌ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ๋ชจ๋ฐฉ ๊ฐ์ฒด๋ก ๋ฐํ๊ฐ์ด ์๋ ๋์์ ๊ตฌํํ์ง ์์ผ๋ฉฐ, ๋ฐํ๊ฐ์ด ์๋ ๋์๋ง ๋ฏธ๋ฆฌ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋๋ก ๊ตฌํํ๋ค.
์ฆ, GetSponsorsUseCase๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ๊ทธ ๋ชจ๋ฐฉ ๊ฐ์ฒด๋ก ๋ฐํ๊ฐ์ ์์ฑํด์ฃผ๋ ์์ ์ ์งํํ๋ ๊ฒ์ด๋ค.
๊ธฐ์กด์ ์๋ ํ ์คํธ ์ฝ๋๋ ์ด๋ฌ๋ค.
private val getSponsorsUseCase: GetSponsorsUseCase = mockk()
Mockk ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด GetSponsorsUseCaseํ์ ์ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์์๋ค.
class StubSponsorRepository(
private val sponsors: List<Sponsor>
) : SponsorRepository {
override suspend fun getSponsors(): List<Sponsor> {
return sponsors
}
}
์ด๋ฅผ Stub์ผ๋ก ๊ตฌํํด์ค๋ค๋ฉด ์ ์ฝ๋์ฒ๋ผ ๋๋ค.
๋ฐํ๊ฐ์ด ์๋ getSponsors ํจ์๋ฅผ ๊ตฌํํด์ฃผ๊ณ ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ sponsors ๋ฐ์ดํฐ๋ฅผ ์ฃผ์ ํด์ค์ผ๋ก์จ ์คํ ์ ๋์ฑ ์ ์ฐํ๊ฒ ๋ง๋ค์ด์ฃผ์๋ค. ๊ทธ๋ฌ๋ฉด ํ ์คํธ์ ํ์ํ ๋ฐ์ดํฐ๊ฐ ๋ค์ด๊ฐ sponsors๋ฅผ StubSponsorRepository ๊ฐ์ฒด ์์ฑ ์ ์ค์ ํ ์ ์๊ฒ ๋๋ค.
given("ํ์์ฌ ๋ฆฌ์คํธ๊ฐ ์กด์ฌํ๋ค๋ฉด") {
beforeTest {
val stubSponsorRepository = StubSponsorRepository(sponsors = fakeSponsors)
viewModel = HomeViewModel(GetSponsorsUseCase(stubSponsorRepository))
}
then("ํ์์ฌ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ ์ ์๋ค") {
runTest {
viewModel.sponsorsUiState.test {
awaitItem()
val actual = awaitItem()
actual.shouldBeInstanceOf<SponsorsUiState.Sponsors>()
}
}
}
}
์ด๊ฒ์ด ์ค์ ์ ์ฉํ ํ ์คํธ ์ฝ๋์ธ๋ฐ, ์ฌ๊ธฐ์๋ ๋ณผ ์ ์๋ฏ์ด fakeSponsors ๋ฆฌ์คํธ๋ฅผ ๋ง๋ค์ด ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ๋ sponsors๋ฅผ ์ค์ ํ ์ ์๋ ๊ฒ์ด๋ค!
Fake
Fake๋ ํ ์คํธ ๋๋ธ์ ์ข ๋ฅ ์ค ํ๋์ด๋ค.
Fake ๊ฐ์ฒด๋, ์ค์ ๊ฐ์ฒด์ ๋น์ทํ๊ฒ ๋์ํ๋๋ก ๊ตฌํ๋ ๋ชจ๋ฐฉ ๊ฐ์ฒด์ด๋ค.
์ฒ์์๋ Stub๊ณผ Fake์ ์ฐจ์ด๊ฐ ๋ฌด์์ธ์ง ํท๊ฐ๋ ธ๋๋ฐ, Stub์ ๋ฐํ๊ฐ์ด ๊ณ ์ ๋์ด ์๋ ๋ฐ๋ฉด Fake๋ ๋ ์ค์ ๊ฐ์ฒด์ฒ๋ผ ๋์ํ ์ ์๋๋ก ๋ด๋ถ ์ํ๊ฐ ์ ๊ตฌ์ฑ๋์ด ์๋ค๋ฉด ๋ณด๋ฉด ๋๋ค.
์๋ฅผ ๋ค์ด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
class FakeSponsorRepository : SponsorRepository {
private val sponsors = mutableListOf<Sponsor>()
override suspend fun getSponsors(): List<Sponsor> {
return sponsors.toList()
}
suspend fun addSponsor(sponsor: Sponsor) {
sponsors.add(sponsor)
}
suspend fun removeSponsor(sponsor: Sponsor) {
sponsors.remove(sponsor)
}
}
DB๋ ๋คํธ์ํฌ๋ฅผ ํตํ ์ ์ฅ ๋์ ์ธ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํด ์ค์ ๊ฐ์ฒด์ฒ๋ผ ๋์ํ๋๋ก ๋ง๋ ๊ฒ์ด๋ค.
์ด๋ค ํ ์คํธ ๋๋ธ์ ์ฌ์ฉํ ์ง๋ ์ํฉ์ ๋ฐ๋ผ ์ ํํด์ฃผ๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
๋จ์ ๊ณ ์ ๋ ๊ฐ๋ง ์ฃผ๋ ๊ฒฝ์ฐ๋ผ๋ฉด Stub์,
๋ฐ์ดํฐ ์ฐ๊ธฐ/์ฝ๊ธฐ ์์ ์ฒ๋ผ ํ์ค์ ์ธ ๋ก์ง์ด ํ์ํ๋ค๋ฉด Fake๋ฅผ ์ฌ์ฉํ๋ฉด ๋๊ฒ ๋ค.
๐๊ด๋ จ PR์ ์ ๋งํฌ์์ ํ์ธ ๊ฐ๋ฅํ๋ค โก๏ธ https://github.com/Kotlin-Multiplatform-Laboratory/DroidKnightsApp-KMP/pull/19
Reference
GitHub - droidknights/DroidKnightsApp: ๊ตญ๋ด ์ต๋ ๊ท๋ชจ ์๋๋ก์ด๋ ์ปจํผ๋ฐ์ค ๋๋ก์ด๋๋์ด์ธ ์ฑ
๊ตญ๋ด ์ต๋ ๊ท๋ชจ ์๋๋ก์ด๋ ์ปจํผ๋ฐ์ค ๋๋ก์ด๋๋์ด์ธ ์ฑ. Contribute to droidknights/DroidKnightsApp development by creating an account on GitHub.
github.com
GitHub - seyoungcho2/coroutinesbook: ใ์ฝํ๋ฆฐ ์ฝ๋ฃจํด์ ์ ์ใ, ์กฐ์ธ์, ์์ด์ฝ ์ถํ์ฌ(2024) ์ ์ฅ์ ์ ๋
ใ์ฝํ๋ฆฐ ์ฝ๋ฃจํด์ ์ ์ใ, ์กฐ์ธ์, ์์ด์ฝ ์ถํ์ฌ(2024) ์ ์ฅ์ ์ ๋๋ค. Contribute to seyoungcho2/coroutinesbook development by creating an account on GitHub.
github.com
'Develop > KMP' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[KMP] Kotest๋ก ํ ์คํธ ์ฝ๋ ๋ฉํฐํ๋ซํผ์ ์ ์ฉํ๊ธฐ (0) | 2025.03.09 |
---|