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

使用Hilt进行单元测试时Nav Controller设置异常问题

解决Fragment测试中NavController未设置的问题

核心原因

你的测试用HiltTestActivity没有配置NavHost容器,且通过viewLifecycleOwnerLiveData设置Mock NavController的时机晚于onViewCreated的执行,导致Fragment初始化时找不到NavController抛出异常。

具体修复方案

1. 修改launchFragmentInHiltContainer扩展函数,提前注入Mock NavController

在启动Fragment前,直接给Fragment的根View绑定Mock NavController,确保在onViewCreated执行前完成绑定:

inline fun <reified T : Fragment> launchFragmentInHiltContainer(
    fragmentArgs: Bundle? = null,
    crossinline action: Fragment.() -> Unit = {},
    navController: NavController? = null // 新增参数接收Mock NavController
) {
    val startActivityIntent = Intent.makeMainActivity(
        ComponentName(
            ApplicationProvider.getApplicationContext(),
            HiltTestActivity::class.java
        )
    )

    ActivityScenario.launch<HiltTestActivity>(startActivityIntent).onActivity { activity ->
        val fragment = activity.supportFragmentManager.fragmentFactory.instantiate(
            T::class.java.classLoader,
            T::class.java.name
        ).apply {
            arguments = fragmentArgs
        }

        activity.supportFragmentManager.beginTransaction()
            .add(android.R.id.content, fragment)
            .commitNow()

        // 提前绑定Mock NavController到Fragment根View
        navController?.let {
            Navigation.setViewNavController(fragment.requireView(), it)
        }

        fragment.action()
    }
}

2. 调整测试代码,传入Mock NavController

在测试中创建Mock实例后,直接通过扩展函数参数传入,确保绑定时机早于Fragment初始化:

@Test
fun testFragmentNavigation() {
    val mockNavController = mock(NavController::class.java)
    
    launchFragmentInHiltContainer<TypeAddFragment>(navController = mockNavController) {
        // 执行测试逻辑,比如触发导航操作
    }

    // 验证导航行为
    verify(mockNavController).navigate(R.id.target_destination)
}

3. (可选)给测试Activity配置NavHost容器

如果Fragment依赖完整导航结构,可在HiltTestActivity布局中添加NavHost,再替换为Mock NavController:

<!-- HiltTestActivity的布局文件 -->
<androidx.fragment.app.FragmentContainerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/test_nav_host"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

测试代码中替换NavController:

@Test
fun testFragmentWithNavHost() {
    val mockNavController = mock(NavController::class.java)
    launchFragmentInHiltContainer<TypeAddFragment> {
        val navHostFragment = requireActivity().supportFragmentManager
            .findFragmentById(R.id.test_nav_host) as NavHostFragment
        navHostFragment.navController = mockNavController
    }
}

关键注意点

  • 必须保证NavController的绑定操作早于onViewCreated执行,这是解决异常的核心。
  • 使用Navigation.setViewNavController()直接绑定View与NavController,无需依赖完整NavHost结构,是测试场景下最直接的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 16:16:12