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

使用Hilt与Navigation组件时Fragment UI测试运行报错如何解决

问题解决方法
  • 错误根本原因:TestNavHostController的导航状态修改方法(包括setGraph、setCurrentDestination)必须在Android主线程执行,当前代码直接在launchFragmentInHiltContainer的回调中调用这些方法,回调运行线程不为主线程,因此抛出异常。

步骤1:修改导航控制器的调用逻辑

将navController的状态修改操作放到主线程执行,修改后的launchWelcomeFragment方法如下:

private fun launchWelcomeFragment() {
    launchFragmentInHiltContainer<WelcomeFragment> {
        // 导航状态修改操作必须运行在主线程
        requireActivity().runOnUiThread {
            navController.setGraph(R.navigation.nav_graph)
            navController.setCurrentDestination(R.id.welcomeFragment)
        }
        viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
            if (viewLifecycleOwner != null) {
                Navigation.setViewNavController(requireView(), navController)
            }
        }
    }
}

步骤2(可选推荐):添加主线程调度规则

在测试类中添加主线程规则,确保协程测试场景下所有操作默认运行在主线程:

@get:Rule
val mainDispatcherRule = MainDispatcherRule()

补充:如果你的项目中没有现成的MainDispatcherRule,可以用以下代码实现:

@OptIn(ExperimentalCoroutinesApi::class)
class MainDispatcherRule(
    val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()
) : TestWatcher() {
    override fun starting(description: Description) {
        super.starting(description)
        Dispatchers.setMain(testDispatcher)
    }

    override fun finished(description: Description) {
        super.finished(description)
        Dispatchers.resetMain()
    }
}

步骤3:检查依赖版本一致性

确保你项目中navigation-testing测试依赖的版本号,和项目主模块使用的Navigation Components版本号完全一致,避免版本不兼容导致的异常。


修改后的完整测试类代码

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
class WelcomeFragmentTest {

    @get:Rule
    val hiltRule = HiltAndroidRule(this)
    
    @get:Rule
    val mainDispatcherRule = MainDispatcherRule()

    private val navController = TestNavHostController(ApplicationProvider.getApplicationContext())

    @Before
    fun setUp(){
        hiltRule.inject()
    }

    @Test
    fun `testFragmentinits`(){
        launchWelcomeFragment()
    }

    private fun launchWelcomeFragment() {
        launchFragmentInHiltContainer<WelcomeFragment> {
            requireActivity().runOnUiThread {
                navController.setGraph(R.navigation.nav_graph)
                navController.setCurrentDestination(R.id.welcomeFragment)
            }
            viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
                if (viewLifecycleOwner != null) {
                    Navigation.setViewNavController(requireView(), navController)
                }
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 10:39:00