使用Hilt进行单元测试时Nav Controller设置异常问题
核心原因
你的测试用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
相关产品推荐
相关产品推荐

