Jetpack Compose仪器测试@HiltViewModel注入报错如何解决?
问题根因
报错的核心原因是Hilt测试环境未向Compose的
viewModel()函数自动提供ViewModel工厂,直接注入@HiltViewModel注解的类会跳过ViewModel的生命周期管理逻辑,因此必须通过Android官方的ViewModelProvider API获取实例。
适配步骤
1. 基础测试类配置
测试类需要添加Hilt测试注解、配置正确的Rule顺序:
@HiltAndroidTest @RunWith(AndroidJUnit4::class) class LandingScreenTest { // HiltRule必须放在ComposeTestRule之前,优先初始化Hilt注入上下文 @get:Rule val hiltRule = HiltAndroidRule(this) @get:Rule val composeTestRule = createComposeRule() @Before fun init() { hiltRule.inject() } }
2. 通过ViewModelProvider构造HiltViewModel实例
在测试的setContent块中,先通过ViewModelProvider从当前Compose上下文的ViewModelStoreOwner中创建ViewModel实例,再传入页面即可,无需修改原有生产代码逻辑:
@Test fun verifyLandingScreenLoginStatusDisplay() { composeTestRule.setContent { MyAppTheme { // 1. 获取当前Compose上下文的ViewModelStoreOwner val storeOwner = LocalViewModelStoreOwner.current!! // 2. 通过ViewModelProvider配合Hilt提供的默认工厂构造ViewModel实例 val loginViewModel = ViewModelProvider( owner = storeOwner, factory = DefaultViewModelFactories.getViewModelFactory( context = LocalContext.current, owner = storeOwner, defaultArguments = null ) )[LoginViewModel::class.java] // 3. 传入手动构造的ViewModel实例到页面 LandingScreen(loginViewModel = loginViewModel) } } // 后续编写测试断言逻辑 composeTestRule.onNodeWithTag("login_btn").assertIsDisplayed() }
3. 可选:页面兼容改造
如果不想每次测试都手动构造实例,可给LandingScreen的ViewModel参数添加默认值,生产环境无需传参,测试环境手动传入即可:
@Composable fun LandingScreen( loginViewModel: LoginViewModel = viewModel() ) { // 原有页面逻辑保持不变 }
常见问题排查
- 若编译时找不到
DefaultViewModelFactories,请确认已引入androidx.hilt:hilt-navigation-compose依赖,版本需与项目Hilt版本对齐 - 若需要隔离Room数据库依赖,可自定义Hilt测试模块替换生产环境的Room实现,使用内存版Room执行测试,无需修改ViewModel原有逻辑
- 测试执行前请确保
HiltRule的初始化顺序优先于ComposeTestRule,避免Hilt注入上下文未初始化导致的实例创建失败
内容的提问来源于stack exchange,提问作者Vahid
相关产品推荐
相关产品推荐

