Kotlin

Kotlin Coroutineのdelay()をユニットテストのときだけ待ち時間なしで実行する

delay()を使ったコードのテストを実行すると、その設定時間だけ待たなきゃいけなくて辛いです。

class MyPrettyStopwatch(

override val coroutineContext: CoroutineContext = Dispatchers.Default
) : CoroutineScope {

var keikaByou: Int = 0
private set

private var job: Job? = null
fun start() {
stop()
keikaByou = 0
job = launch {
while (true) {
println("$keikaByou byou")
delay(1000)
keikaByou += 1
}
}
}

fun stop() {
job?.cancel()
job = null
}
}

class MyPrettyStopwatchTest {

@Test
fun realtimeTest() {
runBlocking {
val stopwatch = MyPrettyStopwatch()
stopwatch.start()
delay(3100) // おっそ!
Assert.assertEquals(3, stopwatch.keikaByou)
}
}
}

そんなときはTestCoroutineDispatcherを使います。


dependencies


build.gradle

dependencies {

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.2.1'
}

TestCoroutineDispatcherkotlinx:kotlinx-coroutines-test1.2.1以降(2019/5/20現在の最新版)に入ってます。


使い方

class MyPrettyStopwatchTest {

@ExperimentalCoroutinesApi
@Test
fun useTestCoroutineDispatcher(){
val dispatcher = TestCoroutineDispatcher()
val stopwatch = MyPrettyStopwatch(dispatcher)
stopwatch.start()
dispatcher.advanceTimeBy(3100) // すぐに実行されてえらい!
Assert.assertEquals(3, stopwatch.keikaByou)
}
}


その他

kotlinx-coroutines-testには他にもコルーチンのテストのためのユーティリティが揃ってます。


  • suspend関数をテストするのはrunBlockingTestが便利そう。


  • Dispatchers.setMain()Main dispatcherを切り替えられる。