You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android单元测试Mockk报错:Missing calls inside every { ... } block

问题分析与解决方案

错误原因

  1. MockK Missing calls异常:
    testParsedResponse是普通String实例,并非MockK创建的mock对象,因此every { testParsedResponse.fromJson<TaskListData>() }的写法无效——MockK只能拦截mock对象的方法调用,无法处理普通对象的扩展函数调用,导致Missing calls inside every { ... } block错误。

  2. 空指针异常:
    单元测试运行在JVM环境,没有完整的Android系统上下文支持。logback初始化时尝试调用Android系统相关API获取外部存储路径,而mock的Context无法提供有效实现,引发NPE。

修复步骤

1. 修复MockK的方法拦截问题

有两种可行方案:

方案A:构造有效JSON字符串,让解析逻辑自然执行

直接让parseJsonFile返回能被fromJson正确解析为TaskListData的JSON字符串,无需mock扩展函数:

@Test
fun `fetchTasks returns expected response`() = runTest {
    // given
    // 匹配TaskListData结构的有效JSON
    val validTaskJson = """{"tasks": []}"""
    val fileName = "tasks.json"
    
    every { context.parseJsonFile(fileName) } returns validTaskJson
    
    // when
    val actualResponse = fetchTasksRepositoryImpl.fetchTasks()
    
    // then
    assertTrue(actualResponse is ApiResponse.Success)
    assertEquals((actualResponse as ApiResponse.Success).data.tasks, emptyList())
}

方案B:用mockkStaticMock扩展函数

如果需要单独验证fromJson的调用逻辑,可使用mockkStatic拦截顶层扩展函数:

@Test
fun `fetchTasks returns expected response`() = runTest {
    // given
    val testParsedResponse = "任意字符串"
    val fileName = "tasks.json"
    val mockTaskData = TaskListData(listOf())
    
    every { context.parseJsonFile(fileName) } returns testParsedResponse
    
    // 替换为你的fromJson扩展函数所在的包路径
    mockkStatic("com.your.app.package.JsonExtensionsKt")
    every { testParsedResponse.fromJson<TaskListData>() } returns mockTaskData
    
    // when
    val actualResponse = fetchTasksRepositoryImpl.fetchTasks()
    
    // then
    assertTrue(actualResponse is ApiResponse.Success)
    assertEquals((actualResponse as ApiResponse.Success).data, mockTaskData)
    
    // 清理mock
    unmockkStatic("com.your.app.package.JsonExtensionsKt")
}

2. 解决logback引发的NPE

在模块级build.gradle中排除MockK依赖中的logback组件,避免Android相关初始化逻辑:

// Groovy DSL
testImplementation("io.mockk:mockk:1.13.8") {
    exclude group: "ch.qos.logback"
}
// Kotlin DSL
testImplementation("io.mockk:mockk:1.13.8") {
    exclude(group = "ch.qos.logback")
}

或者在测试类中提前配置logback避免无效初始化:

@BeforeAll
fun setupTestEnvironment() {
    System.setProperty("logback.configurationFile", "null")
}

内容的提问来源于stack exchange,提问作者Imtiaz Dipto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 03:10:31