Turbine으로 StateFlow와 SharedFlow 테스트하기
Turbine 테스트 라이브러리를 사용해 Flow 기반 상태의 단위 테스트를 작성해 보세요.
Turbine으로 StateFlow와 SharedFlow 테스트하기은(는) CoddyKit의 무료 Kotlin Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Kotlin Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
Turbine을 사용하는 이유
Turbine은 Kotlin Flow를 위한 테스트 라이브러리로, 방출된 값을 쉽게 검증할 수 있게 해 줍니다. Turbine이 없으면 시간 제한을 둔 수동 채널 수집이 필요해 플로를 테스트하기가 번거롭습니다.
// Add to test dependencies:
// testImplementation("app.cash.turbine:turbine:1.0.0")
// testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun main() { println("Turbine + runTest = clean flow testing") }test()를 사용한 기본 플로 테스트
flow.test { }는 플로를 수집하고 awaitItem(), awaitComplete(), awaitError()를 사용해 각 방출을 검증할 수 있게 합니다.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testBasicFlow() = runTest {
val flow = flowOf(1, 2, 3)
flow.test {
assertEquals(1, awaitItem())
assertEquals(2, awaitItem())
assertEquals(3, awaitItem())
awaitComplete()
}
}StateFlow 테스트
StateFlow는 수집할 때 항상 현재 값을 방출합니다. Turbine의 awaitItem()이 이 초기 방출을 가져옵니다.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testStateFlow() = runTest {
val state = MutableStateFlow("loading")
state.test {
assertEquals("loading", awaitItem()) // initial value
state.value = "success"
assertEquals("success", awaitItem())
cancelAndIgnoreRemainingEvents()
}
}SharedFlow 이벤트 테스트
replay=0인 SharedFlow는 앞으로 발생하는 이벤트만 방출합니다. 먼저 수집을 시작한 다음 방출하십시오.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testSharedFlow() = runTest {
val events = MutableSharedFlow<String>()
events.test {
events.emit("LoginSuccess")
assertEquals("LoginSuccess", awaitItem())
events.emit("Navigate")
assertEquals("Navigate", awaitItem())
cancelAndIgnoreRemainingEvents()
}
}가상 시간에 runTest 사용
runTest는 가상 시간을 사용합니다. delay() 호출이 가상 시간을 즉시 진행하므로 지연이 포함된 테스트도 빠르게 실행할 수 있습니다.
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
import app.cash.turbine.*
fun testDelayedFlow() = runTest {
val flow = flow {
delay(1000) // virtual — runs instantly
emit("done")
}
flow.test {
assertEquals("done", awaitItem())
awaitComplete()
}
}예외 테스트에 awaitError 사용
awaitError()는 플로가 예외와 함께 종료되는지 검증합니다. 예상하는 예외 유형과 함께 사용하십시오.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testFlowError() = runTest {
val flow = flow {
emit(1)
throw RuntimeException("stream error")
}
flow.test {
assertEquals(1, awaitItem())
val error = awaitError()
assertEquals("stream error", error.message)
}
}expectNoEvents와 cancelAndIgnoreRemainingEvents
expectNoEvents()는 아무것도 방출되지 않았는지 검증합니다. cancelAndIgnoreRemainingEvents()는 수집을 취소하고 대기 중인 방출을 무시합니다.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testNoEvents() = runTest {
val flow = MutableSharedFlow<Int>()
flow.test {
expectNoEvents() // nothing emitted yet
flow.emit(1)
assertEquals(1, awaitItem())
cancelAndIgnoreRemainingEvents()
}
}Turbine을 사용한 ViewModel 테스트
가짜 저장소를 주입하고 상태 전환을 검증하여 ViewModel의 StateFlow를 테스트하십시오.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
sealed class State { object Loading : State(); data class Data(val v: String) : State() }
class FakeRepo { suspend fun fetch() = "result" }
class VM(repo: FakeRepo, scope: kotlinx.coroutines.CoroutineScope) {
private val _s = MutableStateFlow<State>(State.Loading)
val state = _s.asStateFlow()
init { scope.launch { _s.value = State.Data(repo.fetch()) } }
}
fun testVM() = runTest {
val vm = VM(FakeRepo(), backgroundScope)
vm.state.test {
assertEquals(State.Loading, awaitItem())
val data = awaitItem() as State.Data
assertEquals("result", data.v)
cancelAndIgnoreRemainingEvents()
}
}turbineScope를 사용한 여러 수집기
turbineScope { }를 사용하면 여러 플로를 동시에 테스트할 수 있으며, 각 플로가 자체 Turbine 인스턴스를 가집니다.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testMultipleFlows() = runTest {
val a = MutableStateFlow(1)
val b = MutableStateFlow("x")
turbineScope {
val aTurbine = a.testIn(backgroundScope)
val bTurbine = b.testIn(backgroundScope)
assertEquals(1, aTurbine.awaitItem())
assertEquals("x", bTurbine.awaitItem())
a.value = 2
assertEquals(2, aTurbine.awaitItem())
aTurbine.cancelAndIgnoreRemainingEvents()
bTurbine.cancelAndIgnoreRemainingEvents()
}
}플로 연산자 테스트
Turbine을 사용하여 사용자 지정 플로 연산자와 변환의 동작을 독립적으로 테스트하십시오.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testOperators() = runTest {
(1..5).asFlow()
.filter { it % 2 == 0 }
.map { it * 10 }
.test {
assertEquals(20, awaitItem())
assertEquals(40, awaitItem())
awaitComplete()
}
}가짜 시간 진행을 사용한 테스트
testScheduler.advanceTimeBy()를 사용하면 delay가 포함된 테스트에서 가상 시간을 정밀하게 제어할 수 있습니다.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testTimedFlow() = runTest {
val flow = flow {
emit("start")
delay(500)
emit("end")
}
flow.test {
assertEquals("start", awaitItem())
testScheduler.advanceTimeBy(500)
assertEquals("end", awaitItem())
awaitComplete()
}
}일반적인 실수
핫 플로 테스트가 끝나면 항상 Turbine을 취소하십시오. cancelAndIgnoreRemainingEvents()를 잊으면 테스트가 더 많은 이벤트를 기다리느라 멈출 수 있습니다.
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testGoodPractice() = runTest {
val state = MutableStateFlow(0)
state.test {
awaitItem() // initial 0
state.value = 1
awaitItem() // 1
// Always cancel hot flows:
cancelAndIgnoreRemainingEvents()
}
}빠른 확인
다음에 방출되는 항목을 수집하고 플로가 먼저 완료되거나 오류가 발생하면 예외를 발생시키는 Turbine 함수는 무엇인가요?
요약
Turbine은 awaitItem(), awaitComplete(), awaitError()를 사용해 플로 테스트를 간소화합니다. 가상 시간에는 runTest를 사용하십시오. 핫 플로 테스트는 항상 cancelAndIgnoreRemainingEvents()로 취소하십시오.
AI 튜터와 함께 Kotlin을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 51
- 레슨
- 203
자주 묻는 질문
“Turbine으로 StateFlow와 SharedFlow 테스트하기” 강의는 무료인가요?
네 — “Turbine으로 StateFlow와 SharedFlow 테스트하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Kotlin Academy 강의 전체를 잠금 해제할 수 있습니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“Turbine으로 StateFlow와 SharedFlow 테스트하기”에서 뭘 배우나요?
Turbine 테스트 라이브러리를 사용해 Flow 기반 상태의 단위 테스트를 작성해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Kotlin Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Kotlin Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Kotlin Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“Turbine으로 StateFlow와 SharedFlow 테스트하기” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Kotlin Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Kotlin Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- StateFlow: UI를 위한 핫 상태 보유자
- SharedFlow: 이벤트 버스와 일회성 이벤트
- shareIn과 stateIn으로 콜드 Flow를 핫 Flow로 변환하기
- Turbine으로 StateFlow와 SharedFlow 테스트하기