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

如何验证NavController.navigate()调用,解决Mockito参数相同却报错问题

Mockito测试Compose导航参数校验失败解决方案

常见问题根因

  • 重载匹配错误:NavController的navigate方法存在多个重载(支持Int资源ID、String路由、NavOptions等参数类型),Mockito默认校验时可能匹配到错误的方法签名,即使字面量一致也会抛出参数不匹配错误
  • 常量引用不一致:测试代码和业务代码引用的Constants.SETTINGS_SCREEN_KEY属于不同类(比如多模块同名常量类、测试侧单独定义重名常量),导致Mockito匹配失败

修复方案

方案1:明确指定Mockito参数匹配规则

校验时使用eq匹配器明确指定字符串参数,避免重载匹配错误:

// 错误写法,容易匹配到非字符串的navigate重载
verify(navController).navigate(Constants.SETTINGS_SCREEN_KEY)

// 正确写法,明确匹配字符串参数的navigate重载
verify(navController).navigate(eq(Constants.SETTINGS_SCREEN_KEY))

如果仍有问题,可以添加日志打印确认参数类型:

// 打印实际调用的参数类型和值
doAnswer { invocation ->
    val arg = invocation.getArgument<Any>(0)
    println("实际参数值:${arg.toString()}, 实际参数类型:${arg::class.java.simpleName}")
    println("期望参数值:${Constants.SETTINGS_SCREEN_KEY}, 期望参数类型:String")
    null
}.`when`(navController).navigate(any())

方案2:使用官方TestNavHostController测试(推荐)

这是Android官方推荐的导航测试方案,无需mock,稳定性更高:

  1. 首先添加测试依赖(版本和项目导航库版本保持一致):
debugImplementation "androidx.navigation:navigation-testing:2.7.5"
  1. 测试代码示例:
@get:Rule
val composeTestRule = createComposeRule()

@Test
fun test_settings_navigation() {
    composeTestRule.setContent {
        val testNavController = TestNavHostController(LocalContext.current)
        // 绑定你的导航图,设置起始页为当前测试的页面
        testNavController.setGraph(R.navigation.app_nav_graph)
        testNavController.navigate(Constants.HOME_SCREEN_KEY)

        // 加载目标测试页面
        HomeScreen(navController = testNavController)
    }

    // 执行点击操作
    composeTestRule.onNodeWithContentDescription("设置").performClick()

    // 校验当前目的地路由是否符合预期
    composeTestRule.runOnIdle {
        assertEquals(Constants.SETTINGS_SCREEN_KEY, testNavController.currentDestination?.route)
    }
}

方案3:用ArgumentCaptor捕获参数校验

如果要继续使用Mockito,用参数捕获器获取实际调用的参数再做断言,避开重载匹配问题:

@Test
fun test_settings_navigation() {
    val mockNavController = mock(NavController::class.java)
    // 加载测试页面逻辑...

    // 点击设置按钮...

    // 捕获navigate调用的参数
    val routeCaptor = ArgumentCaptor.forClass(String::class.java)
    verify(mockNavController).navigate(routeCaptor.capture())
    // 断言参数一致
    assertEquals(Constants.SETTINGS_SCREEN_KEY, routeCaptor.value)
}

内容的提问来源于stack exchange,提问作者Lucas Kivi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 01:45:00