如何测试Kotlin挂起函数?单元测试遇类型转换异常
问题根源
这个类型转换异常的核心原因是MockK链式调用的返回值层级错误:
你试图让apollo.buildApolloClient().query(...).execute().data直接返回GetDietaryRestrictionQuery.Data,但实际上execute()方法的返回值是ApolloResponse<GetDietaryRestrictionQuery.Data>,而非Data对象。你的Mock写法相当于强制让execute()返回了Data,导致实际代码调用execute().data时,会把Data对象当成ApolloResponse来处理,触发类型转换错误。
修复方案
需要分层Mock Apollo调用链的每一步,确保每个方法返回对应类型的Mock对象,最后通过ApolloResponse包装你的Data对象返回。
修改后的测试代码如下:
@ExtendWith(MockKExtension::class) internal class RecipeServiceImplTest { @MockK lateinit var apollo: ApolloClientConfig @MockK lateinit var mockApolloClient: ApolloClient @MockK lateinit var mockApolloCall: ApolloCall<GetDietaryRestrictionQuery.Data> @InjectMockKs lateinit var recipeService: RecipeServiceImpl @Test fun getDietaryRestrictionsTest() { val requestConfig = RequestConfig( Optional.presentIfNotNull("en"), Optional.presentIfNotNull(1) ) val stringList: List<String> = listOf("ALCOHOL_FREE", "GLUTEN_FREE", "LACTOSE_FREE") val search: GetDietaryRestrictionQuery.Search = GetDietaryRestrictionQuery.Search(stringList) val data: GetDietaryRestrictionQuery.Data = GetDietaryRestrictionQuery.Data(search) // 1. Mock ApolloClientConfig返回mock的ApolloClient every { apollo.buildApolloClient() } returns mockApolloClient // 2. Mock ApolloClient的query方法返回mock的ApolloCall every { mockApolloClient.query(GetDietaryRestrictionQuery(requestConfig, 999)) } returns mockApolloCall // 3. Mock ApolloCall的execute()方法返回包装了Data的ApolloResponse coEvery { mockApolloCall.execute() } returns ApolloResponse.Builder( request = mockApolloCall.request(), data = data, responseCode = 200 ).build() var result: GetDietaryRestrictionQuery.Data? runBlocking { result = recipeService.getDietaryRestrictions("en", 1) } // 分层验证调用次数 verify(exactly = 1) { apollo.buildApolloClient() } verify(exactly = 1) { mockApolloClient.query(GetDietaryRestrictionQuery(requestConfig, 999)) } coVerify(exactly = 1) { mockApolloCall.execute() } assertEquals(data, result) } }
关键修改点
- 新增
mockApolloClient和mockApolloCall两个Mock对象,分别对应Apollo调用链的不同节点 - 拆分
coEvery为三层,确保每个方法返回正确的类型:buildApolloClient()返回ApolloClientquery(...)返回ApolloCall<Data>execute()返回包装了目标Data的ApolloResponse
- 调整验证逻辑,分层验证每个节点的调用次数,避免链式验证的逻辑错误
内容的提问来源于stack exchange,提问作者engineering_the_future
相关产品推荐
相关产品推荐

