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

MockK模拟失效:调用原始类而非模拟结果的测试问题

问题根源

你猜的没错——B类内部直接实例化了A类,导致测试中创建的mockk<A>()对象和B里的private val a = A()完全是两个独立的实例。B的amend()方法只会调用自己内部创建的原始A实例,根本不会用到你在测试里定义的mock对象,所以MockK自然不生效。

解决方案

方案1:重构B类,使用依赖注入(推荐)

这是最规范的做法,让B类不再硬编码创建A,而是通过构造函数接收A的实例,测试时即可传入mock对象:

修改后的B类代码:

class A {
    fun getName() = "Name"
}

class B(private val a: A) { // 构造函数注入A实例
    fun amend(): String {
        return "${a.getName()}-BName"
    }
}

对应的测试代码:

@Test
fun amendTest() {
    // 创建A的mock实例
    val mockA = mockk<A>()
    // 指定mock行为:调用getName返回空字符串
    every { mockA.getName() } returns ""
    // 将mock实例传入B的构造函数
    val b = B(mockA)
    
    val newName = b.amend()
    
    // 验证mock的getName方法被调用
    verify { mockA.getName() }
    // 断言结果符合预期
    Truth.assertThat(newName).isEqualTo("-BName")
}

方案2:MockK构造函数(适合无法修改原代码的场景)

如果因为历史原因不能修改B类代码,可以用MockK的mockkConstructor拦截A类的构造函数,让B内部创建的A实例自动变成mock对象:

测试代码如下:

@Test
fun amendTestWithConstructorMock() {
    // 拦截A类的构造函数,所有新创建的A实例都是mock
    mockkConstructor(A::class)
    // 设置所有A实例的getName返回空字符串
    every { anyConstructed<A>().getName() } returns ""
    
    val b = B()
    val newName = b.amend()
    
    verify { anyConstructed<A>().getName() }
    Truth.assertThat(newName).isEqualTo("-BName")
    
    // 清理构造函数mock,避免影响其他测试用例
    unmockkConstructor(A::class)
}

注意:这种方式会影响所有测试中A类的实例化,务必在测试完成后用unmockkConstructor清理,防止产生副作用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:45:40