如何在Java中调用MockKKt.verify实现精确次数验证?
这个问题我之前也碰到过,核心原因是Java不支持Kotlin的命名参数,而MockK的verify函数对参数的互斥性有严格校验,咱们一步步来解决:
问题根源分析
先看你写的verifyExactly方法:
public static void verifyExactly(MockkVerifier verifier, int exactly) { MockKKt.verify(Ordering.UNORDERED, false, exactly, Integer.MAX_VALUE, exactly, 0, mockKVerificationScope -> { verifier.verify(mockKVerificationScope); return Unit.INSTANCE; }); }
这里你把atLeast参数也设成了exactly的值,而MockK的校验逻辑(在internalCheckExactlyAtMostAtLeast方法中)会判断:如果同时指定了exactly(非-1)和atLeast/atMost的非默认值,就会抛出specify either atLeast/atMost or exactly异常——因为这两种调用次数的指定方式是互斥的。
在Kotlin里,我们可以用命名参数直接传exactly = n,不用管atLeast和atMost(它们会自动用默认值1和Int.MAX_VALUE),但Java必须按参数顺序传所有值,所以得手动把atLeast和atMost设回默认值。
解决方案1:修正自定义封装的参数
把atLeast设为默认的1,atMost保持Integer.MAX_VALUE,只修改exactly参数:
public static void verifyExactly(MockkVerifier verifier, int exactly) { MockKKt.verify(Ordering.UNORDERED, false, 1, Integer.MAX_VALUE, exactly, 0, mockKVerificationScope -> { verifier.verify(mockKVerificationScope); return Unit.INSTANCE; }); }
这样就不会触发参数互斥的校验了,因为atLeast和atMost用的是默认值,MockK会优先使用exactly的配置。
解决方案2:直接调用MockK的verifyExactly函数
MockK本身就提供了专门的verifyExactly重载,更适合Java调用(不需要处理atLeast/atMost参数):
public static void verifyExactly(MockkVerifier verifier, int exactly) { MockKKt.verifyExactly(Ordering.UNORDERED, false, exactly, 0, mockKVerificationScope -> { verifier.verify(mockKVerificationScope); return Unit.INSTANCE; }); }
这个方法的参数更简洁,完全避开了参数冲突的问题,是更推荐的写法。
验证效果
当你传入exactly = 1时,两种写法都能正确验证方法被精确调用1次,不会再抛出异常。
内容的提问来源于stack exchange,提问作者Kalle Richter

