【问题标题】:Exception in thread "Test worker" java.lang.IllegalStateException: Module with the Main dispatcher had failed to initialize线程“测试工作者”java.lang.IllegalStateException 中的异常:带有主调度程序的模块未能初始化
【发布时间】:2022-01-26 14:07:53
【问题描述】:

嘿,我遇到了这种奇怪的问题。我不明白为什么这会导致我的单元测试。有人可以指导我在我身边缺少什么。

Exception in thread "Test worker" java.lang.IllegalStateException: Module with the Main dispatcher had failed to initialize. For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used
at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.missing(MainDispatchers.kt:118)
at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.isDispatchNeeded(MainDispatchers.kt:96)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:319)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at io.mockk.proxy.jvm.advice.MethodCall.call(MethodCall.kt:14)
at io.mockk.proxy.jvm.advice.SelfCallEliminatorCallable.call(SelfCallEliminatorCallable.kt:14) .....

这是我的单元测试文件。我不明白为什么这会导致问题。

UnitTest.kt

class XYZViewModelTest {

    @get:Rule
    val koinTestRule = KoinTestRule.create {
        modules(utilsModule)
    }

    @get:Rule
    val testInstantTaskExecutorRule: TestRule = InstantTaskExecutorRule()

    private lateinit var mockViewModel: XYZViewModel
    ..../// more declartions
    @Before
    fun setUp() {
        MockKAnnotations.init(this, relaxed = true)
        loadKoinModules(module {
            listOf(
                factory { mockSessionHelper }
            )
        })
        mockViewModel = spyk(XYZViewModel())
    }
     ./// function
}

【问题讨论】:

    标签: android unit-testing kotlin kotlin-coroutines mockk


    【解决方案1】:

    在进行单元测试时,您必须将 Dispatchers.Main 替换为与默认不同的调度程序,因为在未运行完整应用程序时不存在 Dispatchers.Main 的默认实现。为此,如果您还没有 kotlinx-coroutines-test 测试依赖项,则需要:

    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0'
    

    您可以创建一个协程测试规则来在每次测试之前和之后进行设置,这样您就可以在每个测试类中简化处理。

    把它放在它自己的文件中:

    @ExperimentalCoroutinesApi
    class MainDispatcherRule(val dispatcher: TestDispatcher = StandardTestDispatcher()): TestWatcher() {
    
        override fun starting(description: Description?) = Dispatchers.setMain(dispatcher)
    
        override fun finished(description: Description?) = Dispatchers.resetMain()
    
    }
    

    然后将规则添加到您的测试类中:

    @ExperimentalCoroutinesApi
    @get:Rule
    val mainDispatcherRule = MainDispatcherRule()
    

    您使用协程的测试应该使用并返回 runTest 函数,因此它们应该如下所示:

    @ExperimentalCoroutinesApi
    @Test
    fun fooTest() = runTest {
        //...
    }
    

    对不起,如果我错过了什么。最新的kotlinx-coroutines-test 1.6.0 版本有很多变化,我还没跟上。

    【讨论】:

    • 哪里可以在测试中使用这个mainDispatcherRule 变量?
    • 在您在上面的代码中添加的规则之前或之后。
    • 感谢@Tenfour04。
    猜你喜欢
    • 2020-10-07
    • 2020-02-06
    • 1970-01-01
    • 2017-07-30
    • 1970-01-01
    • 2017-03-16
    • 2017-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多