When using kotlin coroutines, how do I unit test a function that calls a suspend function?

13,885

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()
    }
}
Share:
13,885
user1809913
Author by

user1809913

Updated on June 03, 2022

Comments

  • user1809913
    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 inside runBlocking it works as expected but I want to be able to test someFun() all together.

    Any clue how to test a function with both sync and async code?