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
相关产品推荐
相关产品推荐

