如何使用 Hilt 和 Jetpack Compose 在仪器测试中使用导航参数填充 SavedStateHandle

问题描述 投票:0回答:1

我将 Compose、Navigation、ViewModel 和 Hilt 与

SavedStateHandle
结合使用来访问 ViewModel 中的导航参数。一切都运行良好,但是在仪器测试方面我遇到了问题。

假设我有一个 ViewModel:

@HiltViewModel
class MyViewModel @Inject constructor(
    application: Application,
    ...
    savedStateHandle: SavedStateHandle,
) : AndroidViewModel(application) {

    private val id = savedStateHandle.require<Long>("myId")
    ...
}

代表使用 ViewModel 的屏幕的可组合项:

@Composable
fun MyScreen(viewModel: MyViewModel = hiltViewModel()) {
    ...
}

使用 Hilt 呈现可组合项以提供 ViewModel 及其所有依赖项的仪器测试:

@HiltAndroidTest
class MyTest {

    @get:Rule(order = 0)
    val hiltRule by lazy { HiltAndroidRule(this) }

    @get:Rule(order = 1)
    val test by lazy { createAndroidComposeRule<TestActivity>() }

    @Test
    fun shouldRenderScreen() {
        test.setContent { MyScreen() }
        ...
    }
}

当我运行此测试时,应用程序将在

savedStateHandle.require<Long>("myId")
上崩溃,因为
myId
不存在。我无法找到访问或覆盖测试代码中的
SavedStateHandle
的方法。

在应用程序中,

MyScreen
被包裹在
NavHost
中,这使我能够访问
SavedStateHandle
中的导航参数:

@Composable
fun MyApp(
    navController: NavHostController = rememberNavController(),
    startDestination: String = "home",
) {
    ...
    MyTheme {
        NavHost(
            navController = navController,
            startDestination = startDestination,
        ) {
            ...
            composable(
               "route/{myId}", arguments = listOf(
                    navArgument("myId") { type = NavType.LongType }
                )
            ) {
                MyScreen()
            }
            ...
        }
    }
}

现在我意识到,在测试中设置内容时,我可以使用

SavedStateHandle
实例化我自己的 ViewModel 并将其传递到屏幕中,但是我有很多由 Hilt 提供的依赖项,因此需要大量样板文件.

我尝试使用

@BindValue
在测试中提供
SavedStateHandle
,但这会导致重复的绑定错误。我已尝试在测试中使用
@Inject
,但未找到依赖项。
最后,我放弃了测试单屏可组合项的设计,而是将测试内容设置为

SavedStateHandle

通过

MyApp
。这不太理想,因为这个可组合项中还有其他我不想测试的代码。然而,令人惊讶的是,这与
startDestination="route/1"
中的
SavedStateHandle
中没有发现相同的论点问题。
那么有没有一种简单的方法可以在测试中使用导航参数填充 Hilt 提供的 

ViewModel

    

android android-jetpack-compose android-viewmodel android-architecture-navigation dagger-hilt
1个回答
0
投票
SavedStateHandle

从与 ViewModel 关联的

SavedStateHandle
的参数填充其参数 - 当在 NavHost 内部时,这是单独的目的地(这就是为什么带有
ViewModelStoreOwner
的路由填充
"route/{myId}"
参数 - 它如果您的路线是
myId
将不起作用,因为它不包含任何参数)。
当您的测试中没有 

"route/1"

时,它所提取的参数来自 Activity 本身 - 通过 Activity 的

NavHost
上的
extras
因此,您可以在调用 

intent

之前在 Activity 上设置参数,以便在调用

setContent
时它们可用:
hiltViewModel()

© www.soinside.com 2019 - 2024. All rights reserved.