首页 > 解决方案 > 如果我使用 Junit5 和 Rxjava,ViewModel Junit 测试会失败。android.os.Looper 中的方法 getMainLooper 未模拟

问题描述

我正在尝试为我的视图模型编写测试用例,并且我正在使用 junit5 和 mockito。问题是我的测试用例总是失败它给了我这个错误

    at android.os.Looper.getMainLooper(Looper.java)
    at io.reactivex.android.schedulers.AndroidSchedulers$MainHolder.<clinit>

现在我对这个问题做了很多研究,发现这是由于 Rxjava 调度程序,因为它无法在后台线程上运行我按照这个链接并做了所需的步骤,所以之后我的视图模型看起来像这样

MainViewModelTest.kt

@ExtendWith(value = [InstantExecutorExtension::class,TestSchedulerExtension::class])
class MainViewModelTest {


    @Mock
    private lateinit var repository: GithubRepository

    private lateinit var viewModel: MainViewModel

    @Before
    fun init() {
        MockitoAnnotations.initMocks(this)
        viewModel = MainViewModel(repository)
    }

    @Test
    fun testNull(){
        assertThat(viewModel.observeTrendingRepository(), notNullValue())
        verify(repository, never()).makeRequestForTrendingRepo(anyBoolean())
    }

    @Test
    fun fetchTrendingGitHubRepository_emptyDbFirstTimeCase(){

        `when`(repository.makeRequestForTrendingRepo(anyBoolean()))
            .thenReturn(Flowable.just(Resource.Loading(listOf())))

        viewModel.fetchTrendingGitHubRepository(false) // this is where it fails

        assertEquals(Resource.Loading<List<Repository>>(listOf()),LiveDataTestUtil.getValue(viewModel.observeTrendingRepository()));
    }
}

这是分别处理实时数据和 Rxjava 的 InstantExecutorExtension 和 TestSchedulerExtension。

package com.rajat.zomatotest.utils

import androidx.arch.core.executor.ArchTaskExecutor
import androidx.arch.core.executor.TaskExecutor
import org.junit.jupiter.api.extension.AfterEachCallback
import org.junit.jupiter.api.extension.BeforeEachCallback
import org.junit.jupiter.api.extension.ExtensionContext

class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback {

    override fun beforeEach(context: ExtensionContext?) {
        ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() {
            override fun executeOnDiskIO(runnable: Runnable) {
                runnable.run()
            }

            override fun postToMainThread(runnable: Runnable) {
                runnable.run()
            }

            override fun isMainThread(): Boolean {
                return true
            }
        })
    }

    override fun afterEach(context: ExtensionContext?) {
        ArchTaskExecutor.getInstance().setDelegate(null)
    }

}
package com.rajat.zomatotest.utils

import io.reactivex.android.plugins.RxAndroidPlugins
import io.reactivex.plugins.RxJavaPlugins
import io.reactivex.schedulers.Schedulers
import org.junit.jupiter.api.extension.AfterTestExecutionCallback
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback
import org.junit.jupiter.api.extension.ExtensionContext


class TestSchedulerExtension : BeforeTestExecutionCallback, AfterTestExecutionCallback {

    override fun beforeTestExecution(context: ExtensionContext?) {
        RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
        RxJavaPlugins.setComputationSchedulerHandler { Schedulers.trampoline() }
        RxJavaPlugins.setNewThreadSchedulerHandler { Schedulers.trampoline() }
        RxAndroidPlugins.setMainThreadSchedulerHandler { Schedulers.trampoline() }
    }

    override fun afterTestExecution(context: ExtensionContext?) {
        RxJavaPlugins.reset()
        RxAndroidPlugins.reset()
    }

}

我不明白为什么它会给我错误,我已经正确添加了TestSchedulerExtension.kt所以这应该可以工作!!

标签: rx-java2android-testingjunit5android-viewmodel

解决方案


我遇到了同样的问题,我发现解决这个问题的方法是使用

RxAndroidPlugins.setInitMainThreadSchedulerHandler { scheduler }

代替

RxAndroidPlugins.setMainThreadSchedulerHandler { scheduler }

在此链接中,您将找到更多信息。


推荐阅读