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

如何测试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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 02:48:21