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

JUnit测试中使用Mockk库Mock除指定方法外的所有类方法

问题根因

你的测试无法生效有两个核心原因:

  • mockk()创建的是全量Mock对象,所有方法默认不会执行真实逻辑,你未单独配置的method1()本身也被Mock拦截,不会执行内部的分支判断逻辑,自然不会触发method2/method3的调用。
  • 你定义的Parent类中method1、method2、method3均未添加open修饰,Kotlin默认方法为final类型,Mockk默认基于子类重写实现方法拦截,final方法无法被重写拦截,哪怕使用Spy也会出现Mock规则不生效的问题。
实现方案

第一步:调整待测试类的可访问性

如果可以修改源码,给需要拦截/执行真实逻辑的方法添加open修饰,允许Mockk重写拦截:

open class Parent() {
    var condition = true
    open fun method1() {
        if (condition) {
            method2("bum")
        } else {
            method3(41)
        }
    }

    open fun method2(someStr: String): String {
        // 复杂业务逻辑
        return "some result"
    }

    open fun method3(someInt: Int): Int {
        // 复杂业务逻辑
        return 42
    }
}

class Child: Parent() { }

如果你无法修改待测试类源码(比如依赖的第三方类),只需要在测试依赖中引入mockk-agent-jvm依赖,Mockk会通过字节码增强机制自动拦截final类和final方法,不需要修改原类代码即可实现后续的Mock/Spy逻辑。

第二步:使用Spy对象代替全量Mock对象

spyk()创建的是部分Mock(Spy)对象,默认所有方法都会执行真实逻辑,只有你通过every手动指定Mock规则的方法才会返回Mock结果,正好匹配你“保留method1真实执行逻辑,Mock method2、method3返回值”的需求。调整后的测试代码如下:

@Test
fun `when condition is true, it should call method2`() {
    clearAllMocks()

    // 用spyk替代mockk创建实例,默认走真实方法逻辑
    val child: Child = spyk()
    child.condition = true
    // 仅给需要Mock的method2、method3配置返回规则
    every { child.method2(any()) } returns "something"
    every { child.method3(any()) } returns 11

    // 此处调用method1会执行真实逻辑
    child.method1()

    verify(exactly = 1) { child.method2(any()) }
    // 可选校验:condition为true时不会触发method3调用
    verify(exactly = 0) { child.method3(any()) }
}

补充说明

不推荐在全量mockk()实例上通过every { xxx } answers { callOriginal() }的方式逐个配置要保留真实逻辑的方法,这种方式需要手动给所有非Mock方法配置规则,维护成本高,容易漏配导致测试逻辑不符合预期,spyk()是处理这类部分Mock场景的标准方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:51:17