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

Android Kotlin单元测试Mockk报错:every块内缺少模拟调用

解决Android Kotlin单元测试Mockk匹配URL时的报错问题

报错原因

报错io.mockk.MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock的核心问题:

  • Uri.Builder()是构造函数调用,不属于Uri类的静态方法范畴,mockkStatic(Uri::class)仅能mock静态方法,无法处理构造函数调用,因此直接写every { Uri.Builder() }会触发错误。
  • 实际业务代码中并未直接调用Uri.Builder()构造函数,而是通过Uri.parse(url).buildUpon()获取Builder实例,原mock逻辑完全偏离了实际调用链路。

修正后的测试代码

1. 修正setUp方法

@Before
fun setUp() {
    MockKAnnotations.init(this, relaxUnitFun = true)
    // 静态mock Uri类的parse方法
    mockkStatic(Uri::class)
}

2. 修正测试方法

@Test
fun isParamTest() {
    // 创建mock的Uri和Uri.Builder实例
    val mockUri = mockk<Uri>(relaxed = true)
    val mockBuilder = mockk<Uri.Builder>(relaxed = true)
    
    // 定义mock行为:Uri.parse返回mockUri
    every { Uri.parse(any()) } returns mockUri
    // 定义mockUri的buildUpon方法返回mockBuilder
    every { mockUri.buildUpon() } returns mockBuilder
    // 定义mockBuilder的build方法返回预期Uri(转换为字符串后匹配预期值)
    every { mockBuilder.build() } returns Uri.parse("https://test?test=testvalue")

    // 修正变量声明语法错误
    val parameterKey = "test"
    val value = "testvalue"
    val inputURL = "https://test"
    val expected = "https://test?test=testvalue"

    val output = getWebURL(inputURL, parameterKey, value)
    assertThat(output).isEqualTo(expected)
}

关键说明

  • 针对Uri.parse(url).buildUpon()的调用链路,需要分层mock:先让Uri.parse返回mock的Uri对象,再让该mock对象的buildUpon()方法返回mock的Builder对象。
  • 如果需要验证appendQueryParameter的调用逻辑,可以去掉Builder的relaxed = true,显式mock该方法:
    every { mockBuilder.appendQueryParameter(parameterKey, value) } returns mockBuilder
    
    这样可以验证参数是否正确传入。

内容的提问来源于stack exchange,提问作者Android Dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 08:17:24