You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为使用activityViewModels的Fragment编写Instrumentation测试?Mockito无法Mock final类ViewModel的问题及是否需用Mockk的疑问

如何为使用activityViewModels的Fragment编写Instrumentation测试?Mockito无法Mock final类ViewModel的问题及是否需用Mockk的疑问

嗨,太懂你这个头疼的问题了!我之前在测试依赖Activity共享ViewModel的Fragment时,也踩过几乎一模一样的坑,咱们一步步拆解来解决~

先解决Mockito无法Mock final类的问题

你提到试过mock-maker-inline但没生效,大概率是配置位置不对!因为**Instrumentation测试(也就是androidTest目录下的测试)**和普通单元测试的配置路径不一样:

  • 正确的做法是在src/androidTest/resources下创建mockito-extensions文件夹,然后在里面新建org.mockito.plugins.MockMaker文件,文件内容只有一行:mock-maker-inline,注意不要加任何多余的空格、换行或者注释。很多人会不小心把这个文件放到src/test/resources里,导致Instrumentation测试根本读不到配置,自然没法Mock final类。

如果确认配置位置没错还是不行,可以试试升级Mockito的版本,有些旧版本对Kotlin final类的Mock支持有bug,升级到最新稳定版可能会解决。

测试使用activityViewModels的Fragment的正确姿势

当Fragment通过activityViewModels()获取Activity级的ViewModel时,我们需要让测试中的Activity提供我们Mock好的ViewModel实例,具体步骤如下:

  1. 先搞定ViewModel的Mock(不管用Mockito还是后面说的Mockk)
  2. 不用MockViewModelProvider.Factory,写一个简单的自定义工厂更靠谱,避免Mock工厂带来的额外问题:
    // 假设已经Mock好了SomeViewModel
    val mockViewModel = mock(SomeViewModel::class.java)
    
    val testViewModelFactory = object : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return when (modelClass) {
                SomeViewModel::class.java -> mockViewModel as T
                else -> throw IllegalArgumentException("Unknown ViewModel type: ${modelClass.name}")
            }
        }
    }
    
  3. 让Fragment关联的Activity使用这个工厂:
    用FragmentScenario启动Fragment后,在onFragment回调里获取Activity的ViewModelStoreOwner,手动用我们的工厂初始化ViewModel,这样Fragment调用activityViewModels()时就会拿到Mock实例:
    val fragmentScenario = launchFragmentInContainer<YourTargetFragment>()
    
    fragmentScenario.onFragment { fragment ->
        val activityViewModelStore = fragment.requireActivity()
        // 提前用我们的工厂初始化Activity级的ViewModel
        ViewModelProvider(activityViewModelStore, testViewModelFactory)[SomeViewModel::class.java]
    }
    
    这样后续Fragment里调用activityViewModels<SomeViewModel>()就会拿到我们的Mock实例了。

到底要不要用Mockk?

如果Mockito的final类Mock问题实在搞不定,或者你想更顺畅地测试Kotlin代码,Mockk绝对是更优选择:

  • Mockk默认支持Mock final类、object类、静态方法等,不需要额外配置mock-maker-inline这类文件,语法更贴合Kotlin。比如Mock一个final的ViewModel只需要一行:
    val mockViewModel = mockk<SomeViewModel>()
    
  • 它对Kotlin的特性支持更友好,比如协程、扩展函数等,后续测试复杂场景也会更省心。

当然,如果你的项目已经大量使用Mockito,且能搞定mock-maker-inline的配置,继续用Mockito也没问题。但如果配置后还是踩坑,不如直接换Mockk,学习成本不高,能省不少麻烦。

备注:内容来源于stack exchange,提问作者rminaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 15:38:00