시배's Android
Kotlin Coroutines Deep Dive | 15장. 코틀린 코루틴 테스트하기 본문
Book/Kotlin Coroutines Deep Dive
Kotlin Coroutines Deep Dive | 15장. 코틀린 코루틴 테스트하기
si8ae 2024. 2. 12. 16:08TestCoroutineScheduler와 StandardTestDispatcher
- TestCoroutineScheduler는 delay를 가상 시간 동안 실행하여 실제 시간이 흘러간 상황과 동일하게 작동하기 때문에 정해진 시간만큼 기다리지 않도록 변경할 수 있습니다.
- 코루틴에서 TestCoroutineScheduler를 사용하려면, 이를 지원하는 디스패처를 사용해야 합니다.
- 일반적으로 StandardTestDispatcher를 사용합니다.
- 테스트 디스패처로 시작된 코루틴은 가상 시간만큼 진행되기 전까지 실행되지 않습니다.
- StandardTestDispatcher는 TestCoroutineScheduler를 만들기 때문에 명시적으로 만들지 않아도 됩니다.
- StandardTestDispatcher는 직접 시간을 흐르게 하지 않는다는 사실을 명시해야 합니다.
- 시간을 흐르게 하지 않으면 코루틴이 다시 재개되지 않습니다.
- 시간을 흐르게 하는 또 다른 방법은 advancedTimeBy에 일정 밀리초를 인자로 넣어 주는 것입니다.
- 2밀리초와 정확히 일치하는 시간에 예정된 연산을 재개하려면 runCurrent함수를 추가로 호출하면 됩니다.
runTest
- TestScope에서 코루틴을 시작하고 즉시 유휴 상태가 될 때까지 시간을 흐르게 합니다.
- runTest 함수는 다른 함수처럼 스코프를 만들며, 자식 코루틴이 끝날 때까지 기다립니다.
- 절대 끝나지 않는 프로세스를 시작한다면 테스트 또한 종료되지 않습니다.
- backgroundScope는 테스트가 기다릴 필요 없는 모든 프로세스를 시작할 떄 사용합니다.
취소와 컨텍스트 전달 테스트하기
- 특정 함수가 구조화된 동시성을 지키고 있는지 테스트하려면,
- 중단 함수로부터 컨텍스트를 받안 뒤, 컨텍스트가 기대한 값을 가지고 있는지와 잡이 적절한 상태인지 확인하는 것이 가장 쉬운 방법입니다.
@Test
fun `should support cancellation`() = runTest {
var job : Job? = null
val parentJob = launch {
listOf("A").mapAsync {
job = currentCoroutineContext().job
delay(Long.MAX_VALUE)
}
}
delay(1000)
parentJob.cancel()
assertEquals(true, job?.isCancelled)
}
UnconfinedTestDispatcher
- StandardTestDispatcher는 스케줄러를 사용하기 전까지 어떤 연산도 수행하지 않는다는 것이 가장 큰 차이점입니다.
- UnConfinedTestDispatcher는 코루틴을 시작했을 때 첫 번째 지연이 일어나지 전까지 모든 연산을 즉시 수행합니다.
fun main() {
CoroutineScope(StandardTestDispatcher()).launch {
print("A")
delay(1)
print("B")
}
}
디스패처를 바꾸는 함수 테스트하기
@Test
fun `should change dispatcher`() = runBlocking {
// given
val csvReader = mockk<CsvReader>()
val startThreadName = "MyName"
var usedThreadName : String? = null
every {
casvReader.readCsvBlocking(
aFileName,
GameState::class.java
)
} coAnswers {
usedThreadName = Thread.currentThread().name
aGameState
}
val saveReader = SaveReader(csvReader)
// when
withContext(newSingleThreadContext(startThreadName)){
saveReader.readSave(aFileName)
}
// then
assertNotNull(usedThreadName)
val expectedPrefix = "DefaultDispatcher-worker-"
assert(usedThreadName!!.startsWith(expectedPrefix))
'Book > Kotlin Coroutines Deep Dive' 카테고리의 다른 글
Kotlin Coroutines Deep Dive | 17장. 셀렉트 (0) | 2024.02.19 |
---|---|
Kotlin Coroutines Deep Dive | 16장. 채널 (0) | 2024.02.19 |
Kotlin Coroutines Deep Dive | 14장. 공유 상태로 인한 문제 (0) | 2024.02.12 |
Kotlin Coroutines Deep Dive | 13장. 코루틴 스코프 만들기 (0) | 2024.02.05 |
Kotlin Coroutines Deep Dive | 12장. 디스패처 (0) | 2024.02.05 |