如何在测试中初始化带参数的Hilt注入ViewModel
解决Hilt注入ViewModel的测试初始化问题
核心思路
测试ViewModel时,我们只需要验证ViewModel自身的业务逻辑,不需要依赖真实的UseCase实现。因此可以用Mockito模拟(Mock)所有UseCase依赖,完全不需要关心UseCase内部的参数初始化。
具体步骤
- 添加Mockito依赖
在Module级别的build.gradle中添加测试依赖:
testImplementation "org.mockito:mockito-core:5.6.0" androidTestImplementation "org.mockito:mockito-android:5.6.0"
- 正确初始化Mock对象
在测试类中,通过MockitoAnnotations.openMocks(this)自动初始化所有标注@Mock的属性,再用这些Mock对象创建ViewModel:
@RunWith(AndroidJUnit4::class) class ShoppingViewModelTest { @Mock lateinit var addIngredientUseCase: AddIngredientUseCase @Mock lateinit var updateIngredientUseCase: UpdateIngredientUseCase @Mock lateinit var deleteLastIngredientsUseCase: DeleteLastIngredientsUseCase @Mock lateinit var getIngredientsToBuyUseCase: GetIngredientsToBuyUseCase @Mock lateinit var getLastIngredientsUseCase: GetLastBoughtIngedientsUseCase private lateinit var shoppingViewModel: ShoppingViewModel @Before fun setUp() { // 初始化所有@Mock标注的对象 MockitoAnnotations.openMocks(this) // 用Mock依赖实例化ViewModel shoppingViewModel = ShoppingViewModel( addIngredientUseCase, getIngredientsToBuyUseCase, getLastIngredientsUseCase, updateIngredientUseCase, deleteLastIngredientsUseCase ) } @Test fun showDialogChangeTest() { // 编写测试逻辑,比如调用ViewModel方法后验证UseCase的调用行为 // 示例: // shoppingViewModel.triggerDialog() // verify(getIngredientsToBuyUseCase).invoke() } }
- 验证UseCase的调用(关键测试逻辑)
在测试方法中,用Mockito.verify()检查ViewModel是否正确调用了对应的UseCase,确保逻辑符合预期:
@Test fun addIngredientTest() { val testIngredient = Ingredient("牛奶") // 调用ViewModel的添加方法 shoppingViewModel.addIngredient(testIngredient) // 验证AddIngredientUseCase是否被调用,且参数匹配 verify(addIngredientUseCase).invoke(testIngredient) }
为什么不需要关心UseCase内部的参数?
Mock对象是一个“假实现”,它不会执行真实的业务逻辑,只会记录被调用的次数、传入的参数等信息。我们的测试目标是验证ViewModel的逻辑是否正确,UseCase自身的逻辑应该单独编写测试用例来覆盖。
内容的提问来源于stack exchange,提问作者Martí Curto
相关产品推荐
相关产品推荐

