使用MockK测试时Mock Uri报错Can't Find Stub如何解决?
问题原因
- 你没有正确mock
Models类的静态成员:Models.APPOINTMENT.contentUri是Models类的成员属性,不属于Uri类的静态方法范畴,你当前只调用了mockkStatic(Uri::class),完全没有对Models类做mock配置,MockK自然找不到对应的stub规则。 - 额外mock
Uri类静态方法但没有配置对应stub:你mock了Uri的静态类后,调用Uri.parse、Uri.withAppendedPath时没有配置对应的返回规则,这两个方法返回的是临时生成的未stub的mock Uri对象,进一步触发了找不到stub的报错。
解决方案
根据你的测试环境可以任选以下两种方案:
方案一:使用Robolectric(推荐,可直接调用安卓系统API真实实现)
引入Robolectric测试框架,直接调用真实的Uri工具方法,仅mock需要的Models类成员即可,修改后代码如下:
import org.robolectric.RobolectricTestRunner import org.junit.runner.RunWith @RunWith(RobolectricTestRunner::class) class GetNavigationModelTest { @MockK lateinit var mockContentResolver: ContentResolver private val useCaseUnderTest = GetNavigationModel() @Before fun setup() { MockKAnnotations.init(this) // 针对Models类做静态mock,若Models是Kotlin object类则改用mockkObject(Models) mockkStatic(Models::class) // 有Robolectric支持可直接调用Uri的真实方法 val testUri = Uri.withAppendedPath(Uri.parse(BASE_URI), UUID) every { Models.APPOINTMENT.contentUri } returns testUri // 补充contentResolver query方法的stub,避免后续调用时报错 every { mockContentResolver.query(eq(testUri), any(), any(), any(), any()) } returns mockk(relaxed = true) } @Test fun myTest() { useCaseUnderTest.invoke(mockContentResolver, UUID) assert(true) } @After fun teardown() { // 清除静态mock,避免污染其他测试用例 unmockkStatic(Models::class) } companion object { private const val BASE_URI = "content://com.example.provider" private const val UUID = "appointment" } }
方案二:无需Robolectric,直接mock Uri实例
如果不想引入Robolectric,完全不需要mock Uri的静态方法,直接构造mock Uri实例赋值即可:
class GetNavigationModelTest { @MockK lateinit var mockContentResolver: ContentResolver @MockK lateinit var mockUri: Uri private val useCaseUnderTest = GetNavigationModel() @Before fun setup() { MockKAnnotations.init(this) // 针对Models类做静态mock,若Models是Kotlin object类则改用mockkObject(Models) mockkStatic(Models::class) every { Models.APPOINTMENT.contentUri } returns mockUri // 补充contentResolver query方法的stub every { mockContentResolver.query(eq(mockUri), any(), any(), any(), any()) } returns mockk(relaxed = true) } @Test fun myTest() { useCaseUnderTest.invoke(mockContentResolver, UUID) assert(true) } @After fun teardown() { unmockkStatic(Models::class) } companion object { private const val UUID = "appointment" } }
内容的提问来源于stack exchange,提问作者AndroidDev
相关产品推荐
相关产品推荐

