Testing Coroutines on Android (Android Dev Summit '19)
Why Stack Overflow recommends it
Stack Overflow users link it when answering how to unit test coroutines, especially injecting dispatchers, overriding the Main dispatcher with test rules, and fixing threading problems in suspend function tests.
Recommended by 3 people across 3 different months, 2018 to 2020.
What it is
A 20-minute Android Dev Summit 2019 talk by Manuel Vivo and Sean McQuillan on testing Kotlin coroutines in Android apps. It covers testing code that uses Dispatchers.Main, controlling the timing of events in tests, and why Dispatchers.Unconfined is a poor choice.
What people said
Strong rec Emmanuel · 2020-01 · Stack Overflow · on “Kotlin Coroutine Testing with Dispatchers.IO”
According to Google: [LINK] Dispatchers should be injected into your ViewModels so you can properly test. You are setting the TestCorotutineDispatcher as the main Dispatcher via Dispatchers.setMain which takes control over the MainDispatcher , but you still have no control over the the execution of the coroutine launched via viewModelScope.launch(Dispatchers.IO) . Passing the Dispatcher via the constructor would make sure that your test and production code use the same dispatcher. Typically an @Rule is defined that: Overrides the MainDispatcher via Dispatchers.setMain (like you are doing) Uses the TestCoroutineDispatcher's own runBlockingTest() to actually run the test. Here [this video] is a rea
Recommends Long Ranger · 2020-03 · Stack Overflow · on “How to test livedata with coroutine in unit test”
After few days searching on the internet. I find out how to do the unit test with coroutine in livedata and come up with the following ideas. It might not be the best idea but hope it can bring some insight to the people who have similar problems. There are few necessary parts for coroutine unit test with livedata: Need to add 2 rules for the unit test ( Coroutine Rule, InstantExecutor Rule [LINK] ). If you use Junit5 like me, you should use extensions instead. Coroutine Rule provide the function for you to use the testCoroutine dispatcher in Java UnitTest . InstantExecutor Rule provide the function for you to monitor the livedata emit value in Java UnitTest . And be careful coroutine.dispat
Recommends Stachu · 2020-08 · Stack Overflow · on “Mockito's `thenReturn` returns `null` instead of Pair(null."text") when called by tested class and not directly”
it's because the funtions are suspend functions, specyfing dispatcher in runBlocking fixed it for me where I found an answer: testing coroutines in Android [this video] @Test fun createUserFailDueToUserExisting() = runBlocking(Dispatchers.IO) { val user = "user" val pass = "pass" val mks = mock(MyKeyStore::class.java) `when`(mks.createKeyStore(user, pass)).thenReturn(Pair(null, "userExists")) println(mks.createKeyStore(user, pass)) val repo = UserRepo(mks) val result = repo.createUser(user, pass, pass) assertFalse(result.first) assertTrue(result.second == "userExists") }
Cites Nikolay Kulachenko · 2018-04 · Stack Overflow · on “How to unit test Kotlin suspending functions”
I've found out that it's because of a CoroutineDispatcher . I used to mock UI context with EmptyCoroutineContext . Switching to Unconfined has solved the problem Update 02.04.20 The name of the question suggests that there'll be an exhaustive explanation how to unit test a suspending function. So let me explain a bit more. The main problem with testing a suspending function is threading. Let's say we want to test this simple function that updates a property's value in a different thread: class ItemUpdater(val item: Item) { fun updateItemValue() { launch(Dispatchers.Default) { item.value = 42 } } } We need to somehow replace Dispatchers.Default with an another dispatcher only for testing purp
Cites Emmanuel Mtali · 2020-05 · Stack Overflow · on “Kotlin coroutine unit test fails with "Module with the Main dispatcher had failed to initialize"”
UPDATE 2024 Add the following dependency on your gradle. Documentation here [LINK] testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" Add the following Custom TestRule as a utility for your tests // Reusable JUnit4 TestRule to override the Main dispatcher @OptIn(ExperimentalCoroutinesApi::class) class MainDispatcherRule( private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher() ) : TestWatcher() { override fun starting(description: Description) { Dispatchers.setMain(testDispatcher) } override fun finished(description: Description) { Dispatchers.resetMain() } } In your test do the following @get:Rule val mainDispatcherRule = MainDispatcherRule