Kotlin+Compose中ViewModel测试Mockk报错:Missing mocked calls问题
解决MockK测试ViewModel时的"Missing mocked calls"错误
错误原因分析
你遇到的Missing mocked calls inside every { ... } block错误,核心问题是错误地在every块中直接引用mock实例,而不是调用mock的方法或属性。MockK的every语法要求块内必须是对mock对象的方法/属性调用,直接写mock对象本身的写法完全不符合规则,导致MockK无法识别这是有效的mock调用,进而抛出异常。
看你代码里的这些无效写法:
every { mockProduct1 } returns product1 every { mockProduct2 } returns product2 every { mockGroupProduct1 } returns groupProduct1 every { mockGroupProduct2 } returns groupProduct1
修复步骤
1. 移除无效mock或修正mock行为
如果Product和GroupProduct是数据类,且测试中不需要模拟它们的复杂行为,直接使用真实实例即可,不需要mock,这会让测试逻辑更简洁:
// 直接创建真实数据实例,无需mock val product1 = Product(id = 1, name = "Test 1") val product2 = Product(id = 2, name = "Test 2") val groupProduct1 = GroupProduct(product = product1, quantity = 5) val groupProduct2 = GroupProduct(product = product2, quantity = 3)
如果确实需要mock这些类(比如它们包含需要模拟的方法),要针对具体方法或属性设置mock行为,例如:
val mockProduct1 = mockk<Product>() // 模拟id属性的返回值 every { mockProduct1.id } returns 1 // 模拟name属性的返回值 every { mockProduct1.name } returns "Test 1"
2. 清理冗余mock
你的MyPantryViewModel构造函数只接收了mockGetGroupProductListUseCase和mockObserveAllProductsUseCase,代码中定义的mockGetGroupProductUseCase并未被使用,可以直接移除,减少不必要的代码复杂度。
3. 完整修复后的测试代码示例
class MyPantryViewModelTest { @Test fun `given viewmodel initialized when ui state observed then ui state is Empty`() { // 直接使用真实数据实例 val product1 = Product(id = 1, name = "Test 1") val product2 = Product(id = 2, name = "Test 2") val expectedProductList = listOf(product1, product2) val groupProduct1 = GroupProduct(product = product1, quantity = 5) val groupProduct2 = GroupProduct(product = product2, quantity = 3) val groupsProduct = listOf(groupProduct1, groupProduct2) // Mock UseCase(这部分写法是正确的) val mockGetGroupProductListUseCase = mockk<GetGroupProductListUseCase>() every { mockGetGroupProductListUseCase.invoke(any()) } returns groupsProduct val mockObserveAllProductsUseCase = mockk<ObserveAllProductsUseCase>() every { mockObserveAllProductsUseCase.invoke() } returns flowOf(expectedProductList) // given val viewModel = MyPantryViewModel(mockGetGroupProductListUseCase, mockObserveAllProductsUseCase) // when val uiState = viewModel.uiState.value // then assertTrue(uiState is MyPantryUiState.Empty) } }
额外注意事项
- 如果用
lazy初始化mock,要确保在every块之前已经触发初始化(比如提前调用一次mockProduct1),避免因mock未初始化导致的异常。 - 遵循最小mock原则:只mock需要模拟行为或返回值的类,纯数据模型尽量用真实实例,降低测试的维护成本。
内容的提问来源于stack exchange,提问作者Mateusz Hermanowicz
相关产品推荐
相关产品推荐

