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

升级fragment-testing到1.5.3后,Spy Fragment无法访问ViewModel报错

解决androidx.fragment:fragment-testing:1.5.3中Spy Fragment触发ViewModelStore访问错误的问题

问题场景

升级androidx.fragment:fragment-testing从1.4.x版本到1.5.3后,使用Mockito spy包装的Fragment在Robolectric测试中出现以下错误:

Can't access ViewModels from detached fragment at androidx.fragment.app.Fragment.getViewModelStore for spy(fragment) object

  • 普通Fragment实例的测试可正常通过,仅Spy Fragment触发该错误
  • 切换到FragmentScenario测试同样报错
  • 问题仅出现在Robolectric + Mockito的测试环境中
  • 测试代码示例:
activity = Robolectric.buildActivity(AppCompatActivity::class.java).setup().get()
activity.supportFragmentManager.beginTransaction().add(android.R.id.content, fragment).commit()
if (idleLooper) {
    shadowOf(getMainLooper()).idle()
}

原因分析

Fragment 1.5.x版本对生命周期状态的校验逻辑做了强化,而Mockito默认的spy代理会拦截Fragment的所有方法调用,包括isDetached()这类判断生命周期状态的方法。即使Fragment已经通过Transaction添加并完成commit,spy的代理可能没有正确传递真实Fragment的状态,导致框架误判Fragment仍处于detached状态,进而在访问ViewModelStore时抛出异常。

解决方案

方案1:创建Spy时指定调用真实方法

使用Mockito的CALLS_REAL_METHODS作为默认答案,确保生命周期状态相关方法调用真实Fragment的实现,避免状态判断出错:

val fragment = spy(
    MyFragment(contact, mockViewModel, mockFragmentManager),
    withSettings().defaultAnswer(CALLS_REAL_METHODS)
)

方案2:手动存根状态判断方法

如果不需要所有方法都调用真实实现,可以单独存根isDetached()方法,让它返回正确的状态:

val fragment = spy(MyFragment(contact, mockViewModel, mockFragmentManager))
`when`(fragment.isDetached()).thenReturn(false)

方案3:改用FragmentFactory注入依赖

Fragment 1.5+推荐使用FragmentFactory来注入依赖,避免直接通过构造函数传入Mock的FragmentManager,减少状态冲突的概率:

// 自定义测试用FragmentFactory
class TestFragmentFactory(
    private val contact: Contact,
    private val viewModel: MyViewModel
) : FragmentFactory() {
    override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
        return when (className) {
            MyFragment::class.java.name -> MyFragment(contact, viewModel)
            else -> super.instantiate(classLoader, className)
        }
    }
}

// 测试中使用FragmentFactory启动Fragment
val scenario = FragmentScenario.launchInContainer(
    MyFragment::class.java,
    null,
    TestFragmentFactory(contact, mockViewModel)
)

验证

以上任意方案都可以让Spy Fragment在1.5.3版本的测试中正常访问ViewModelStore,恢复和1.4.x版本一致的测试行为。

内容的提问来源于stack exchange,提问作者Ankit Jangid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 18:43:12