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

MockK中wasNot called跨测试校验失败问题排查与解决

MockK wasNot called跨测试校验失败问题解决

问题场景

使用MockK的wasNot called校验类是否被调用时出现异常:当前测试用例未调用目标类,但只要同测试类中其他用例调用过该类的mock实例,当前校验就会失败。

代码示例

class ClassA {
  fun method(): Int = 1
}

class ClassB(val classA: ClassA, var call: Boolean = true) {
  fun method(): Int = if(call) classA.method() else 0
}

class MyTest: FreeSpec({
  "Test" - {
    val mockClassA = mockk<ClassA>()
    val sut = ClassB(mockClassA)

    "methodA called" - {
      every { mockClassA.method() } returns 1

      sut.method()

      verify { mockClassA.method() }
    }

    "methodA not called" - {
      every { mockClassA.method() } returns 1
      sut.call = false

      sut.method()

      verify { mockClassA wasNot called } // 此处失败
    }
  }
})

错误信息

Verification failed: ClassA(#1) should not be called:

问题原因

核心问题是mock实例的作用域共享:
你将mockClassA和被测对象sut定义在了外层的"Test"块中,这两个实例会被所有子测试用例复用。第一个测试用例执行时调用了mockClassA.method(),这个调用记录会被持久保存在mock实例中;第二个测试用例执行时,mock实例的历史调用记录没有被清空,导致wasNot called校验检测到了之前的调用痕迹,最终失败。

解决方法

方法1:每个测试用例使用独立的mock实例

将mock和被测对象的定义移到每个子测试用例内部,确保每个用例拥有完全独立的mock实例,避免调用记录交叉影响:

class MyTest: FreeSpec({
  "Test" - {
    "methodA called" - {
      val mockClassA = mockk<ClassA>()
      val sut = ClassB(mockClassA)
      every { mockClassA.method() } returns 1

      sut.method()

      verify { mockClassA.method() }
    }

    "methodA not called" - {
      val mockClassA = mockk<ClassA>()
      val sut = ClassB(mockClassA)
      every { mockClassA.method() } returns 1
      sut.call = false

      sut.method()

      verify { mockClassA wasNot called }
    }
  }
})

方法2:测试前清空mock的调用记录

如果需要保留外层的实例定义,可以在每个测试用例执行前,调用clearMocks函数清空mock的历史调用记录:

class MyTest: FreeSpec({
  "Test" - {
    val mockClassA = mockk<ClassA>()
    val sut = ClassB(mockClassA)

    // 每个测试用例执行前清空mock的调用记录
    beforeTest {
      clearMocks(mockClassA)
      // 如果连mock的存根(every定义)也需要重置,添加answers=true参数:
      // clearMocks(mockClassA, answers = true)
    }

    "methodA called" - {
      every { mockClassA.method() } returns 1

      sut.method()

      verify { mockClassA.method() }
    }

    "methodA not called" - {
      every { mockClassA.method() } returns 1
      sut.call = false

      sut.method()

      verify { mockClassA wasNot called }
    }
  }
})

注意:如果你的mock存根(every定义)也需要在每个测试前重置,需要给clearMocks添加answers = true参数,否则存根会保留之前的定义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 16:25:55