Mock父类无Setter属性值失败求助(Java+Kotlin混合项目)
问题诊断与解决方案
核心原因拆解
CALLS_REAL_METHODS的使用误区:若创建Mock时指定了该策略,父类getValue()会优先执行真实实现(返回默认空字符串),即使通过whenever尝试Stub,也可能因Mockito的执行逻辑导致覆盖失效——该策略下,未被显式Stub的方法会调用真实逻辑,但部分场景下父类方法的Stub优先级低于真实调用。- final方法限制:检查Lombok生成的
getValue()是否为final方法(例如父类添加了@EqualsAndHashCode等会隐式使getter变为final的注解),Mockito无法代理final方法,自然无法修改其返回值。 - 依赖版本不兼容: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.
相关产品推荐
相关产品推荐

