使用Mockk测试Firebase Realtime Database异步函数getUsers时类型转换失败问题
使用Mockk测试Firebase Realtime Database异步函数getUsers时类型转换失败问题
我帮你分析下这个问题,你遇到的java.lang.Object cannot be cast to GETUsers错误,主要是因为mock的设置和泛型处理没到位,咱们一步步来解决:
问题根源
getValue的mock方式错误:你在测试里写了every { snapshot.getValue<GETUsers>()!! } returns expectedResult,但实际上getValue<GETUsers>()本身返回的是GETUsers?类型,你把非空断言!!也包含进mock匹配里,mockk没办法正确识别这个泛型函数的调用,导致实际运行时getValue返回默认的Object类型mock,进而触发类型转换异常。mockkTask的默认result干扰:你的mockkTask函数里默认给result设置了一个relaxed=true的mock对象,虽然你后续在测试里重新mock了task.result返回自定义的snapshot,但这种重复mock容易引发预期外的问题。
解决方案
1. 修复mockkTask函数
让它支持直接传入预设的result值,避免后续重复mock,同时更贴合测试场景:
private inline fun <reified T> mockkTask( exception: Exception? = null, result: T? = null ): Task<T> { return mockk<Task<T>>(relaxed = true) { every { isComplete } returns true every { this@mockk.exception } returns exception every { isCanceled } returns false // 如果传入了result就用传入的值,否则用relaxed mock result?.let { every { this@mockk.result } returns it } ?: run { every { this@mockk.result } returns mockk(relaxed = true) } } }
2. 修正测试里的mock逻辑
- 直接用自定义的
snapshot创建task,不需要后续再mocktask.result - 正确mock
getValue<GETUsers>()函数,去掉多余的!! - 确保
getValue返回非空的expectedResult,匹配原代码里的非空断言
修改后的测试代码:
@Test fun `getUsers() called should return success with two users`() = runBlocking { val user01 = GETUser() val user02 = GETUser() val user01ID = "exampleUser01ID" val user02ID = "exampleUser02ID" val users = mutableMapOf(user01ID to user01, user02ID to user02) val expectedResult = GETUsers(users) // 1. 创建snapshot并mockgetValue返回预期结果 val snapshot: DataSnapshot = mockk() every { snapshot.getValue<GETUsers>() } returns expectedResult // 2. 用自定义的snapshot创建task,避免重复mock val task: Task<DataSnapshot> = mockkTask(result = snapshot) // 3. mock数据库引用的get方法返回task every { databaseReference.get() } returns task // 4. 执行测试并断言 val result = repository.getUsers() println(result) Assert.assertTrue(result is Resource.Success) val successResult = result as Resource.Success Assert.assertEquals(2, successResult.data.users.size) Assert.assertEquals(user01, successResult.data.users[user01ID]) Assert.assertEquals(user02, successResult.data.users[user02ID]) }
3. 额外注意点
- 确保
GETUser和GETUsers类重写了equals和hashCode方法,否则Assert.assertEquals会因为对象引用不同而失败。 - 原代码里的
getValue<GETUsers>()!!依赖于数据库一定有值,在测试里我们已经mock了getValue返回非空结果,所以不会触发空指针。
这样修改后,mock的逻辑更清晰,泛型类型也能正确匹配,应该就能解决你遇到的类型转换错误了。
备注:内容来源于stack exchange,提问作者Kleini
相关产品推荐
相关产品推荐

