使用launchFragmentInHiltContainer时如何向Fragment传入自定义ViewModel
解决方案
你可以通过以下两种主流方案实现自定义ViewModel实例注入,无需修改生产代码中viewModel的val声明:
方案1:使用Hilt测试绑定替换依赖(推荐,无侵入)
该方案利用Hilt的测试依赖替换能力,直接替换ViewModel构造参数中的依赖,无需手动赋值Fragment的viewModel变量:
- 确认你的
HomeFragmentViewModel添加了@HiltViewModel注解,且依赖通过构造函数注入,示例:
@HiltViewModel class HomeFragmentViewModel @Inject constructor( private val repository: Repository // 你真实的Repository接口/父类 ) : ViewModel() { // 业务逻辑 }
- 在测试类中使用
@BindValue注解直接绑定你的FakeRepository实例,Hilt创建ViewModel时会自动使用该实例:
@RunWith(AndroidJUnit4::class) @LargeTest @HiltAndroidTest @ExperimentalCoroutinesApi class MainFragmentTest { @get:Rule var hiltRule = HiltAndroidRule(this) // 新增绑定,直接替换全局的Repository实现 @BindValue val fakeRepository: Repository = FakeRepository() @Before fun init() { hiltRule.inject() } @Test fun testFragmentDisplays() { // 无需额外赋值操作,Fragment内的viewModel会自动使用上述fakeRepository初始化 val scenerio = launchFragmentInHiltContainer<MainFragment>() } }
方案2:反射修改val属性(应急方案,不推荐用于常规测试)
如果你有特殊场景需要完全自定义ViewModel实例,可以通过反射跳过val的访问限制直接赋值:
@Test fun testFragmentDisplays() { val fakeRepository = FakeRepository() val customViewModel = HomeFragmentViewModel(fakeRepository) val scenerio = launchFragmentInHiltContainer<MainFragment> { fragment -> val viewModelField = MainFragment::class.java.getDeclaredField("viewModel") // 如果你使用的是Kotlin委托属性,需要修改字段名为「viewModel\$delegate」,并修改委托值 viewModelField.isAccessible = true viewModelField.set(fragment, customViewModel) } }
注意:该方案依赖字段名固定,生产代码修改变量名后测试会失效,仅建议临时调试使用。
内容的提问来源于stack exchange,提问作者sadat
相关产品推荐
相关产品推荐

