如何在Robolectric测试中为NavHost可组合项传入必填导航参数
问题
我想在Robolectric测试中传入必填导航参数,以运行底层可组合项。我的代码基于TiVi应用旧版本的导航实现,但该项目没有相关测试。
实现代码如下:
fun NavGraphBuilder.addTopLevelComposable( navController: NavHostController, ... etc ) { addLowLevelComposable( navController = navController, ... etc ) } private fun NavGraphBuilder.addLowLevelComposable( navController: NavHostController, ... etc ) { composable( LeafScreen.LowLevelDetails.route, arguments = listOf( navArgument("id") { type = NavType.StringType nullable = false }, ), ) { backStackEntry -> val arguments = checkNotNull(backStackEntry.arguments) val id = checkNotNull(arguments.getString("id")) // 使用id的代码逻辑 } }
测试代码如下:
@Test fun `addTopLevelComposable- low level destination - asserts something`() { composeTestRule.setContent { NavHost( navController = rememberNavController(), // 这个参数没有被正确处理!为什么? startDestination = LeafScreen.LowLevelDetails.createRoute("this is an id"), ) { addTopLevelComposable( navController = navHostController, // 其他参数 ) } } // 断言逻辑 } data object LowLevelDetails: LeafScreen("home/lowlevel/{id}") { fun createRoute(id: String): String = "home/lowlevel/$id" }
目前测试中设置的startDestination参数未被正确处理,请问该如何实现必填导航参数的正确传递?
解决方法
问题核心是:直接把带参数的字符串路由设为startDestination时,导航组件只会把整个字符串当作路由名,不会自动解析其中的参数占位符并填充到backStackEntry.arguments里。可以通过以下两种方式解决:
方式一:手动创建带参数的起始BackStackEntry
初始化NavHostController时,手动构建包含参数的起始条目,替代直接设置startDestination:
@Test fun `addTopLevelComposable- low level destination - asserts something`() { composeTestRule.setContent { val navController = rememberNavController() LaunchedEffect(Unit) { // 构建带参数的Bundle val args = bundleOf("id" to "this is an id") // 初始化导航图并传入参数 navController.setGraph( navController.navInflater.inflate(R.navigation.your_nav_graph), args ) } NavHost( navController = navController, // 无需再设置startDestination ) { addTopLevelComposable( navController = navController, // 其他参数 ) } } // 断言逻辑 }
如果没有XML导航图,可以直接代码构建导航图:
LaunchedEffect(Unit) { val navGraph = navController.createGraph( startDestination = LeafScreen.LowLevelDetails.route, route = "root" ) { addTopLevelComposable( navController = navController, // 其他参数 ) } navController.setGraph(navGraph, bundleOf("id" to "this is an id")) }
方式二:用navigate方法跳转目标路由
初始化NavHost后,通过navigate方法跳转到带参数的路由,确保参数被正确解析:
@Test fun `addTopLevelComposable- low level destination - asserts something`() { composeTestRule.setContent { val navController = rememberNavController() NavHost( navController = navController, // 设置临时起始页(或直接用目标路由) startDestination = "temp_start" ) { // 临时起始页(仅用于初始化) composable("temp_start") {} addTopLevelComposable( navController = navController, // 其他参数 ) } // 手动跳转到带参数的目标页面 LaunchedEffect(Unit) { navController.navigate(LeafScreen.LowLevelDetails.createRoute("this is an id")) } } // 断言逻辑 }
内容的提问来源于stack exchange,提问作者Alix
相关产品推荐
相关产品推荐

