Spock Mock对象字段无法更新问题求助
问题重现
我们有这样一个简单类:
class Apple { Color color; boolean isFresh; }
测试时用Mock创建Apple实例,调用业务方法后,明明方法里给color字段赋了值,但断言时发现它始终是null:
测试代码:
Apple apple = Mock(Apple.class); myService.myMethod(apple); assert apple.color == Color.RED; // 失败,apple.color一直是null
待测试的myMethod实现:
public void myMethod(Apple apple) { apple.color = Color.RED; }
问题根源
Mock框架(比如Mockito)生成的Mock对象本质是动态代理类,默认不会维护真实的字段状态。它的核心是模拟方法调用的返回或行为,而非像真实对象那样存储字段值。直接给Mock对象的字段赋值,操作的是代理类的临时字段,后续读取时框架依然会返回默认值(比如null)。
解决思路
这里给三种可行的解决办法:
1. 用Spy替代Mock
Spy是对真实对象的包装,会保留对象的原生行为,包括字段的读写逻辑。如果你的测试只需要模拟Apple类的部分方法,同时要保留字段的真实存储,用Spy最合适:
Apple apple = Spy(new Apple()); myService.myMethod(apple); assert apple.color == Color.RED; // 断言成功
2. 配置Mock支持字段访问(以Mockito为例)
如果必须用Mock,可以通过配置让框架允许字段的实际读写。比如在Mockito中开启宽松模式,或者显式定义字段的get行为:
// 开启宽松模式,允许未存根的字段/方法调用 Apple apple = Mockito.mock(Apple.class, Mockito.withSettings().lenient()); // 如果你给Apple加了color的getter方法,还可以显式存根get行为 doAnswer(invocation -> invocation.getMock().color).when(apple).getColor();
注意:如果是直接操作字段而非通过getter,还是优先用Spy更省心。
3. 直接使用真实对象
如果Apple类没有复杂依赖,测试场景也不需要模拟任何方法,直接new一个真实实例是最直接的方案:
Apple apple = new Apple(); myService.myMethod(apple); assert apple.color == Color.RED; // 断言成功
内容的提问来源于stack exchange,提问作者Mike U
相关产品推荐
相关产品推荐

