Espresso测试中launchFragmentInContainer传Integer触发NPE问题
Integer参数UI测试触发NullPointerException的解决思路
业务代码中从参数获取Integer的Fragment运行正常,但编写UI测试时,调用TestNavHostController.setCurrentDestination(R.id.MyFragment)触发NullPointerException,报错栈如下:
java.lang.NullPointerException: null cannot be cast to non-null type kotlin.Int at androidx.navigation.NavType$Companion$IntType$1.get(NavType.kt:320) at androidx.navigation.NavType$Companion$IntType$1.get(NavType.kt:310) at androidx.navigation.NavArgument.verify(NavArgument.kt:76) at androidx.navigation.NavDestination.addInDefaultArgs(NavDestination.kt:603) at androidx.navigation.NavController.navigate(NavController.kt:1855) at androidx.navigation.NavController.handleDeepLink(NavController.kt:1414) at androidx.navigation.testing.TestNavHostController.setCurrentDestination(TestNavHostController.kt:51) at androidx.navigation.testing.TestNavHostController.setCurrentDestination$default(TestNavHostController.kt:47) at com.wolfpackdigital.extrakarte.base.BaseUITest.setupNavigation(BaseUITest.kt:130)
当前测试场景初始化代码:
val bundle = bundleOf( "myParam" to 3 ) scenario = launchFragmentInContainer(themeResId = R.style.AppTheme, fragmentArgs = bundle)
其他类型参数(如String、自定义数据模型)均可正常工作,仅Integer参数出现问题,解决思路如下:
问题根源
TestNavHostController.setCurrentDestination()方法会自动验证目标Fragment在导航图中定义的参数规则。如果你的MyFragment导航参数myParam被定义为非空Int类型,但调用setCurrentDestination时未传入该参数,导航组件会尝试用默认值(默认是null)填充,而Kotlin非空Int无法接受null,直接触发类型转换NPE。注意:launchFragmentInContainer传入的fragmentArgs是给Fragment实例的,和导航组件的参数验证逻辑是两个独立流程,无法覆盖导航参数的校验。
可行解决方案
1. 调用setCurrentDestination时传入参数bundle
直接在设置当前目的地时,带上符合要求的参数bundle,让导航组件通过参数校验:
val navArgs = bundleOf("myParam" to 3) navController.setCurrentDestination(R.id.MyFragment, navArgs)
2. 调整导航图中参数的可空性(按需使用)
如果业务允许myParam为空,可以修改导航图中该参数的配置:
- 在导航图XML中,给
myParam添加android:defaultValue="@null",并设置app:nullable="true" - 或者在Kotlin的导航安全参数类中,将
myParam定义为Int?(可空类型)
但此方法可能违背业务需求,需谨慎评估。
3. 封装带参数的导航设置方法(优化复用)
如果多个测试用例都需要设置该目的地,可以在BaseUITest中封装一个方法,自动带上必填参数:
fun setupMyFragmentNavigation() { val navArgs = bundleOf("myParam" to 3) navController.setCurrentDestination(R.id.MyFragment, navArgs) }
内容的提问来源于stack exchange,提问作者E. P.B.
相关产品推荐
相关产品推荐

