runTest over runBlocking

During a recent code review, I got curious?why runTest over runBlocking while both execute suspending code block in synchronise behaviour.

Time advancing

One major benefit is the ability to skip delay and advance the time to future. Imaging running the following code with runBlocking, I bet you'll ever see this in your production code but bare with me and this following unit test block would take 10 second to complete. ??

    @Test
    fun `demonstrate virtual time advancement`() = runBlocking {
        var counter = 0
        
        launch {
            delay(10_000) // 10 seconds delay
            counter++
        }
        
        // Test completes after 10-second delay
        assertEquals(1, counter)
    }        

However, with a slight change from runBlocking to runTest, the same test now completes instantly.

 @Test
    fun `demonstrate virtual time advancement`() = runTest {
       ...
    }        

That is because runTest use special test dispatcher to intercept the delay and return continuation with virtual timestamp. [source]


TestDispatcher

Let's slightly tweak the previous code and add custom dispatcher.

The output produce the result similar to runBlocking that the test complete with 10-second delay even with runTest . By default, runTest CANNOT skip delays on real dispatchers (like Dispatchers.IO) in child coroutines.

 @Test
    fun `demonstrate virtual time advancement`() = runTest {
       ....
        launch(Dispatchers.IO) { // ?? Real dispatcher
            delay(10_000) // 10 seconds delay
            counter++
        }
        ...
    }        

To skip delays, one option is to inject special test dispatcher which runTest internally use.

val testDispatcher = StandardTestDispatcher(testScheduler)
launch(testDispatcher) { // ? Test dispatcher
    delay(10_000) // 10 seconds delay 
    ...
}        

Hence one of the best practices is to always look out for an opportunity to inject dispatcher for one's customViewModel class instead of directly launching coroutine with explicit dispatcher.

要查看或添加评论,请登录

社区洞察

其他会员也浏览了