Paulius Ruminas
04/09/2020, 9:19 AMTestCoroutineScope
for my test but it loops forever. Simplified test case:
@Test
fun a() = runBlockingTest {
launch {
while(true) {
delay(60_000)
println("called")
}
}
advanceTimeBy(70_000)
}
What am I missing?wasyl
04/09/2020, 9:29 AMTestCoroutineScope
ignore all delays by default? I believe you need to call pauseDispatcher
if you want to manually advance clock (and maybe trigger actions with runCurrent()
)tseisel
04/09/2020, 9:37 AMrunBlockingTest
block has completed, if there are still running coroutines then the test won't cancel them and may suspend forever. You probably need to cancel the Job returned by launch
yourself, after performing assertions.Paulius Ruminas
04/09/2020, 10:11 AMrunBlockingTest
will not end. It looks weird to me that advanceUntilTime
kinda does not do what the name suggest it won't "stop" the time. It would be nice that I could call stop()
or something on the dispatcher ant it would "stop" the virtual time.wasyl
04/09/2020, 10:27 AMI could call stop() or something on the dispatcher ant it would “stop” the virtual time.How does
stop()
that you suggest differ from the existing pauseDispatcher()
method?Paulius Ruminas
04/09/2020, 11:10 AMpauseDispatcher
does nothing in the given example it will still run indefinitely:
@Test
fun a() = runBlockingTest {
pauseDispatcher()
launch {
while (true) {
delay(60_000)
println("called")
}
}
advanceTimeBy(70_000)
}
What I meant by stop
is this:
@Test
fun a() = runBlockingTest {
launch {
while (true) {
delay(60_000)
println("called")
}
}
advanceTimeBy(70_000)
stop() // clear the queue
// prints called only once
}
I think advanceByTime
should work like this by default. If one specified advance time by 70_000 it should stop after that time unless there are other caveats that I'm missing.tseisel
04/09/2020, 11:49 AMrunBlockingTest
usually fail fast if some coroutines are still running (and suspended) after test block ends.
It seems that in this case, advancing time actually makes the launched coroutine react to it, conflicting with this feature.
For the time being, you should be able to cancel running coroutines with the following code (which is equivalent to what you'd expect from a stop
function):
coroutineContext.cancelChildren()
Paulius Ruminas
04/09/2020, 11:54 AMlouiscad
04/09/2020, 12:01 PMJob
returned by launch
, call cancel()
on it and problem gone, logic correct.Paulius Ruminas
04/09/2020, 12:19 PMTestDispatcher
implementation. Currently there is no way to stop the dispatcher from running automatically.louiscad
04/09/2020, 12:21 PMwhile(true) {
Paulius Ruminas
04/09/2020, 12:46 PMsuspend fun runIndefinitely() {
while (true) {
delay(60_000)
println("I'm called every minute")
}
}
@Test
fun test1() = runBlockingTest {
val explicitJobOnlyForTest = Job()
try {
launch(coroutineContext + explicitJobOnlyForTest) {
runIndefinitely()
}
advanceTimeBy(120_000)
} finally {
explicitJobOnlyForTest.cancelAndJoin()
}
}
But I would like that TestDispatcher would let me avoid all of this explicit cancellation like this:
@Test
fun test2() = runBlockingTest {
launch {
runIndefinitely()
}
advanceTimeBy(120_000)
// currently does not work since runBlockingTest calls advanceUntilIdle
}
louiscad
04/09/2020, 2:01 PMJob
from the scope/coroutineContext should.