Reputation: 7
I followed https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/ , looks like runBlockingTest is skipping the delay coroutine and I’m not able to reach the code after delay from main function. Is there a good way unit test/advance the timer and assert flags accordingly?
can you please help me to unit test my main function
// my main function is having multiple delay coroutines to set a flag true/false
fun delayFunction() {
launch { // coroutine scope
isFlag = false
delay(1000)
isFlag = true
delay(1000)
isFlag = false
}
}
// I tried unit testing something like this
@Test
fun `test delayFunction`() {
runBlockingTest {
delayFunction()
advanceTimeBy(1001)
assertThat(isFlag).isTrue()
advanceTimeBy(1001)
assertThat(isFlag).isFalse()
}
}
Upvotes: -1
Views: 1868
Reputation: 657
For anyone looking into this problem, you can check out: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-test/, specifically Controlling the virtual time
where you can check in-between delays:
@Test
fun testFoo() = runTest {
launch {
val workDuration = testScheduler.timeSource.measureTime {
println(1) // executes during runCurrent()
delay(1_000) // suspends until time is advanced by at least 1_000
println(2) // executes during advanceTimeBy(2_000)
delay(500) // suspends until the time is advanced by another 500 ms
println(3) // also executes during advanceTimeBy(2_000)
delay(5_000) // will suspend by another 4_500 ms
println(4) // executes during advanceUntilIdle()
}
assertEquals(6500.milliseconds, workDuration) // the work took 6_500 ms of virtual time
}
// the child coroutine has not run yet
testScheduler.runCurrent()
// the child coroutine has called println(1), and is suspended on delay(1_000)
testScheduler.advanceTimeBy(2.seconds) // progress time, this will cause two calls to `delay` to resume
// the child coroutine has called println(2) and println(3) and suspends for another 4_500 virtual milliseconds
testScheduler.advanceUntilIdle() // will run the child coroutine to completion
assertEquals(6500, currentTime) // the child coroutine finished at virtual time of 6_500 milliseconds
}
For my case, I had to something similar:
@Test
fun testFoo() = runTest {
launch {
myMethodWithDelaysInside()
}
testScheduler.runCurrent()
// Assert my flag here
assertTrue(myFlag)
testScheduler.advanceTimeBy(2.seconds) // progress time, this will cause two calls to `delay` to resume
// Assert that my flag has changed
assertFalse(myFlag)
}
Upvotes: 1