To test Coroutines running on Dispatchers.Main
you need kotlinx-coroutines-test library.
💡 At the time of writing the
kotlinx-coroutines-test
library is marked as experimental. May have breaking changes.
Example
package com.example.android.kotlincoroutines.main
/* ...imports */
class MainViewModelTest {
@get:Rule
val coroutineScope = MainCoroutineScopeRule()
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
lateinit var subject: MainViewModel
@Before
fun setup() {
subject = MainViewModel(
TitleRepository(
MainNetworkFake("OK"),
TitleDaoFake("initial")
)
)
}
@Test
fun whenMainClicked_updatesTaps() {
subject.onMainViewClicked()
Truth.assertThat(subject.taps.getValueForTest()).isEqualTo("0 taps")
coroutineScope.advanceTimeBy(1000)
Truth.assertThat(subject.taps.getValueForTest()).isEqualTo("1 taps")
}
}
Two rules are used to allow us to test MainViewModel in an off-device test.
In the setup
method, a new instance of MainViewModel
is created using testing fakes of network and database.
For this test, the fakes are only needed to satisfy the dependencies of MainViewModel
.
By calling onMainViewClicked
, the coroutine will be launched. This test checks that the taps text stays "0 taps" right after onMainViewClicked
is called, then 1 second later it gets updated to "1 taps".
This test uses virtual-time to control the execution of the coroutine launched by onMainViewClicked
thanks to the MainCoroutineScopeRule. Here we're calling advanceTimeBy(1_000)
which will cause the main dispatcher to immediately execute coroutines that are scheduled to resume 1 second later.
This test is fully deterministic. Because it has full control over the execution of coroutines launched on the Dispatchers.Main
it doesn't have to wait one second for the value to be set.