简体   繁体   中英

Kotlin coroutines unit testing with runBlocking does not wait for execution

Is there any way to wait for a suspending function that is running in a scope, like what runBlocking does for its running suspending functions?

For example,

class CoroutineTestCase : CoroutineScope {
    val job = Job()
    var value = 1
    override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Unconfined


    fun testFunction() {
         async {
             delay(2000)
             value = 2
        }
    }
}

@Test
fun testCoroutine() = runBlocking {
    val coroutineTestCase = CoroutineTestCase()
    coroutineTestCase.testFunction()
    assertEquals(2, coroutineTestCase.value)
}

The above test fails with value being 1 and not changed (since the launch was not being waited to finish). If the testFunction had been a suspending function and I ran it with runBlocking inside my unit test, everything would have worked.

I've tried with other custom dispatchers (like the one below) that can blockingly run their tasks, but no luck

class TestUiContext : CoroutineDispatcher() {
     override fun dispatch(context: CoroutineContext, block: Runnable) {
         block.run()
    }
}

Okay so I figured out what is happening. The launch is not awaited because its returned value is never used.

In the example above, the testFunction should return the returned value of launch, which is a Deffered object that can be awaited/joined. So to actually wait for its completion, the code has to be changed as below:

class CoroutineTestCase : CoroutineScope {
    val job = Job()
    var value = 1
    override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Unconfined


    fun testFunction(): Deferred<Unit> {
         return async {
                 delay(20000)
                 value = 2
        }
    }
}

@Test
fun testCoroutine() = runBlocking {
    val coroutineTestCase = CoroutineTestCase()
    coroutineTestCase.testFunction().await()
    assertEquals(2, coroutineTestCase.value)
}

Currently the only problem is that, in this case, it actually delays 20 seconds (with the unconfined dispatcher).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM