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

Mock父类无Setter属性值失败求助(Java+Kotlin混合项目)

问题诊断与解决方案

核心原因拆解

  1. CALLS_REAL_METHODS的使用误区:若创建Mock时指定了该策略,父类getValue()会优先执行真实实现(返回默认空字符串),即使通过whenever尝试Stub,也可能因Mockito的执行逻辑导致覆盖失效——该策略下,未被显式Stub的方法会调用真实逻辑,但部分场景下父类方法的Stub优先级低于真实调用。
  2. final方法限制:检查Lombok生成的getValue()是否为final方法(例如父类添加了@EqualsAndHashCode等会隐式使getter变为final的注解),Mockito无法代理final方法,自然无法修改其返回值。
  3. 依赖版本不兼容:Mockito Kotlin与Mockito核心版本不匹配时,可能出现Stub逻辑不生效的情况。

可行解决办法

方案1:正确Mock父类方法(无需反射)

放弃CALLS_REAL_METHODS,直接MockMyClass并Stub父类的getValue():

import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever

val myClassMock = mock<MyClass>()
// Kotlin可以直接调用属性语法
whenever(myClassMock.value).thenReturn("自定义非空值")
// 或者显式调用getter方法
whenever(myClassMock.getValue()).thenReturn("自定义非空值")

// 验证生效
assert(myClassMock.value == "自定义非空值")

若需保留MyClass自身方法的真实实现,改用Spy(对真实对象做部分Mock):

import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever

val myClassSpy = spy(MyClass())
whenever(myClassSpy.getValue()).thenReturn("自定义非空值")

// 此时MyClass自身方法执行真实逻辑,父类getValue()返回Stub值

方案2:解除final方法限制

若ParentClass的getValue()是final方法,修改Lombok配置生成非final getter(需Lombok 1.18.16+):

@MappedSuperclass
@Getter(nonFinal = true)
public class ParentClass {
  private String value = "";
}

重新编译后,即可正常Mock该方法。

方案3:反射兜底(仅备选)

若无法修改父类代码,可通过反射直接修改私有属性:

import java.lang.reflect.Field

val myClass = MyClass()
val valueField = ParentClass::class.java.getDeclaredField("value")
valueField.isAccessible = true
valueField.set(myClass, "自定义非空值")

assert(myClass.value == "自定义非空值")

额外说明

  • Jakarta的@Entity和@MappedSuperclass注解不影响Mockito的Mock行为,这些仅在JPA持久化流程中生效,与测试对象的Mock逻辑无关。
  • Kotlin与Java互操作本身无问题,确保Mockito Kotlin依赖版本与Mockito核心匹配(例如testImplementation "org.mockito.kotlin:mockito-kotlin:4.1.0"对应Mockito核心4.x版本)。

内容的提问来源于stack exchange,提问作者J.F.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 00:40:56