渐进式编程课
KMP 目录
第 29 课2026.08.14

导航图写对并不代表按钮一定连到了正确页面。共享导航测试可以确认 Android 与 iOS 共用的 NavHost 在用户点击后确实显示目标页面。

第 29 课:Compose 共享导航测试

知识点

在 commonTest 中通过真实点击验证 Compose Multiplatform 的页面跳转。

用途

导航图写对并不代表按钮一定连到了正确页面。共享导航测试可以确认 Android 与 iOS 共用的 NavHost 在用户点击后确实显示目标页面。

核心概念

  • 把导航图提取为可单独装载的 AppNavHost()。
  • 页面组件只接收导航回调,不直接依赖 NavController,便于独立测试。
  • 测试使用 runComposeUiTest 装载真实导航图。
  • 优先执行真实点击,再断言目标页面是否显示。
  • 本课继续使用第 25 课已经添加的 Compose UI 测试依赖,无需新增测试库。

示例代码

先定义一个最小导航图:

kotlin
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlinx.serialization.Serializable

@Serializable
data object Home

@Serializable
data object Detail

@Composable
fun HomeScreen(onOpenDetail: () -> Unit) {
    Button(onClick = onOpenDetail) {
        Text("打开详情")
    }
}

@Composable
fun AppNavHost(
    navController: NavHostController = rememberNavController(),
) {
    NavHost(
        navController = navController,
        startDestination = Home,
    ) {
        composable<Home> {
            HomeScreen(
                onOpenDetail = { navController.navigate(Detail) },
            )
        }

        composable<Detail> {
            Text("详情页")
        }
    }
}

然后在 commonTest 中模拟点击:

kotlin
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.v2.runComposeUiTest
import kotlin.test.Test

class NavigationTest {
    @OptIn(ExperimentalTestApi::class)
    @Test
    fun clickDetail_navigatesToDetail() = runComposeUiTest {
        setContent {
            AppNavHost()
        }

        onNodeWithText("打开详情").performClick()

        onNodeWithText("详情页").assertIsDisplayed()
    }
}

这条测试验证的是完整链路:按钮点击 → navigate(Detail) → NavHost 显示详情页。

5 分钟练习

给详情页增加“返回首页”按钮并调用 popBackStack();测试先进入详情页,再点击返回按钮,最后断言“打开详情”重新显示。

参考答案

详情页:

kotlin
composable<Detail> {
    Button(onClick = { navController.popBackStack() }) {
        Text("返回首页")
    }
}

测试代码:

kotlin
onNodeWithText("打开详情").performClick()
onNodeWithText("返回首页").performClick()

onNodeWithText("打开详情").assertIsDisplayed()

与上一课的联系

上一课用 popBackStack() 和 popUpTo() 设计返回栈行为;今天开始用自动化测试验证这些导航操作是否真的把用户带到正确页面。

参考资料