Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error calling Dispatchers.setMain() in unit test

Have started to try to use kotlinx-coroutines-test (https://github.com/Kotlin/kotlinx.coroutines/blob/master/core/kotlinx-coroutines-test/README.md) in JUnit unit test but getting following error when i call Dispatchers.setMain()

java.lang.IllegalArgumentException: TestMainDispatcher is not set as main dispatcher, have Main[missing, cause=java.lang.AbstractMethodError: kotlinx.coroutines.test.internal.TestMainDispatcherFactory.createDispatcher()Lkotlinx/coroutines/MainCoroutineDispatcher;] instead.

    at kotlinx.coroutines.test.TestDispatchers.setMain(TestDispatchers.kt:22)

I've tried calling Dispatchers.setMain(Dispatchers.Unconfined) and also passing in val mainThreadSurrogate = newSingleThreadContext("UI thread"). It looks like issue isn't anyway with value being passed in but rather it's tripping up in mainDispatcher test in following

public fun Dispatchers.setMain(dispatcher: CoroutineDispatcher) {
    require(dispatcher !is TestMainDispatcher) { "Dispatchers.setMain(Dispatchers.Main) is prohibited, probably Dispatchers.resetMain() should be used instead" }
    val mainDispatcher = Dispatchers.Main
    require(mainDispatcher is TestMainDispatcher) { "TestMainDispatcher is not set as main dispatcher, have $mainDispatcher instead." }
    mainDispatcher.setDispatcher(dispatcher)
}
like image 342
John O'Reilly Avatar asked Jan 06 '19 13:01

John O'Reilly


People also ask

Why dispatchers are not available during unit tests in Android?

This is because the Dispatchers.Main uses Android main looper which is not available during unit tests. That’s available in instrumentation tests but not in unit tests. We need to solve the problem by replacing the Dispatchers with a TestCoroutineDispatcher, which allows us to control the execution of the coroutines when we are doing tests.

What is the difference between dispatchers setmain and testcoroutinedispatcher?

Note that Dispatchers.setMain is only needed if you use viewModelScope or you hardcode Dispatchers.Main in your codebase. TestCoroutineDispatcher is a dispatcher that gives us control of how coroutines are executed, being able to pause/resume execution and control its virtual clock.

How to test coroutine dispatchers other than main?

Inject Dispatcher to test Coroutine Dispatchers other than Dispatchers.Main e.g., Dispatchers.IO For the demonstration of the project, we will be using the following three dependencies: A suspending function is a function that can be paused and resumed at a later time.

How to test your dispatcher?

So far, we have found ways to test our Dispatcher.IO and Dispatcher.Main Coroutines. By default, Coroutines work for Dispatcher.Main, but to test Dispatcher.IO, we have to use the TestCoroutineDispatcher for replacing the main dispatchers with the test dispatcher.


2 Answers

Try adding core as a dependency on your test. It solved the problem for me.

testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.0")

like image 127
yigit Avatar answered Oct 09 '22 04:10

yigit


Turned out issue was I was using older version of kotlinx-coroutines-core dependency. When I updated to v1.1.0 it worked (thanks @vigit for helping trigger that realisation!)

like image 3
John O'Reilly Avatar answered Oct 09 '22 04:10

John O'Reilly