如何测试Jetpack Compose用户点击导航并注入假数据?
解决Jetpack Compose导航测试中无法传入假用户列表的问题
核心思路是Mock UserListScreen依赖的ViewModel,让它返回假用户数据,这样UserListScreen就能把假数据传给UserListContent,进而可以模拟点击测试导航逻辑。以下是具体实现步骤:
1. 准备测试依赖
确保Module级别的build.gradle包含Compose测试和ViewModel测试相关依赖:
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.5.4" debugImplementation "androidx.compose.ui:ui-test-manifest:1.5.4" testImplementation "androidx.arch.core:core-testing:2.2.0" androidTestImplementation "androidx.navigation:navigation-testing:2.7.5"
2. Mock ViewModel返回假用户列表
根据项目的ViewModel创建方式,选择对应的Mock方案:
手动创建ViewModel场景
如果项目未用依赖注入框架,直接写一个返回假数据的ViewModel实现:
class FakeUserListViewModel : UserListViewModel { override val users = MutableStateFlow(listOf( User(id = 1, name = "测试用户1"), User(id = 2, name = "测试用户2") )) }
Hilt依赖注入场景
用MockK或Mockito来mock ViewModel,指定返回假数据:
@HiltAndroidTest class UserNavigationTest { @get:Rule val hiltRule = HiltAndroidRule(this) @Mock lateinit var userListViewModel: UserListViewModel @Before fun setup() { hiltRule.inject() // 配置ViewModel返回假用户列表 coEvery { userListViewModel.users } returns flowOf(listOf( User(id = 1, name = "测试用户1") )) } }
3. 使用TestNavHostController测试导航逻辑
用Compose测试库提供的TestNavHostController替代真实导航控制器,跟踪导航动作并断言:
@RunWith(AndroidJUnit4::class) class UserNavigationTest { @get:Rule val composeTestRule = createAndroidComposeRule<ComponentActivity>() private lateinit var navController: TestNavHostController @Before fun setupNavHost() { composeTestRule.setContent { navController = rememberTestNavHostController() // 传入Mock的ViewModel val fakeViewModel = FakeUserListViewModel() YourAppTheme { NavHost( navController = navController, startDestination = "user_list" ) { composable("user_list") { UserListScreen(viewModel = fakeViewModel) } composable( "user_details/{userId}", arguments = listOf(navArgument("userId") { type = NavType.IntType }) ) { backStackEntry -> val userId = backStackEntry.arguments?.getInt("userId") ?: 0 UserDetailsScreen(userId = userId) } } } } } @Test fun clickUserItem_navigatesToUserDetails() { // 等待列表项渲染完成 composeTestRule.onNodeWithText("测试用户1").assertExists() // 模拟点击列表项 composeTestRule.onNodeWithText("测试用户1").performClick() // 断言是否导航到目标页面 composeTestRule.runOnIdle { assertEquals( "user_details/1", navController.currentBackStackEntry?.destination?.route ) } } }
关键说明
- 无需直接给
UserListContent传假数据,它的数据源是UserListScreen依赖的ViewModel,从ViewModel层Mock数据才是合理路径。 rememberTestNavHostController是导航测试的核心工具,能跟踪所有导航动作,方便验证目的地是否正确。- 用
runOnIdle()确保Compose完成界面重组后再执行断言,避免异步渲染导致的测试失败。
内容的提问来源于stack exchange,提问作者Always Learner
相关产品推荐
相关产品推荐

