When using kotlin coroutines, how do I unit test a function that calls a suspend function?
Fixing async
As implemented, your someFun()
will just “fire and forget” the async
result. As a result, runBlocking
does not make a difference in that test.
If possible, make someFun()
return async
's Deferred
and then, in runBlocking
, call await
on it.
fun someFun(): Deferred<Unit> {
// ... Some synchronous code
return async {
suspendFun()
}
}
Then the test:
runBlocking {
SomeClass().someFun().await()
}
This question/answer is a good resource for further information.
alternative: use launch
It's also possible to avoid async
in favor of using suspend
functions and a launch
-created coroutine:
suspend fun someFun() {
// ... Some synchronous code
suspendFun()
}
private suspend fun suspendFun() {
delay(1000)
println("executed")
// ... other code
}
The test uses launch
and the outer runBlocking
implicitly waits for its completion:
val myScope = GlobalScope
runBlocking {
myScope.launch {
SomeClass().someFun()
}
}
user1809913
Updated on June 03, 2022Comments
-
user1809913 almost 2 years
I have a class like this
class SomeClass { fun someFun() { // ... Some synchronous code async { suspendfun() } } private suspend fun suspendFun() { dependency.otherFun().await() // ... other code } }
I want to unit test
someFun()
so I wrote a unit test that looks like this:@Test fun testSomeFun() { runBlocking { someClass.someFun() } // ... verifies & asserts }
But this doesn't seem to work because runBlocking doesn't actually block execution until everything inside runBlocking is done. If I test
suspendFun()
directly insiderunBlocking
it works as expected but I want to be able to testsomeFun()
all together.Any clue how to test a function with both sync and async code?