如何验证Mockito mock调用时传入的可变对象在后续变更前的特定状态
问题原因说明
原有测试失败的核心原因:Mockito的
verify动作是在业务方法执行完成后才执行,此时传入的可变对象已经被后续逻辑修改了状态,默认的参数匹配是基于修改后的对象状态做equals比较,自然和预期的调用时状态不符。
解决方案
通用方案:通过Answer在调用发生时实时捕获参数快照
该方案无需修改现有业务类,在mock方法被调用的瞬间(此时对象还未被后续逻辑修改)就保存状态快照,后续直接校验快照即可,兼容所有Mockito版本。
import org.junit.Test; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @Test public void operationIsCalledWithSpecificState() { StatefulOperation operation = mock(StatefulOperation.class); // 存储调用时的参数状态快照 AtomicReference<Stateful> capturedCallInput = new AtomicReference<>(); // 定义mock方法的回调逻辑,调用时立刻保存参数状态 when(operation.doOperation(any(Stateful.class))).thenAnswer(invocation -> { Stateful input = invocation.getArgument(0); // 基于当前状态创建副本存入,避免后续对象修改影响快照 capturedCallInput.set(new Stateful(input.getValue())); return null; // 如果doOperation有返回值按实际类型返回即可 }); StatefulService statefulService = new StatefulService(operation); statefulService.execute(new Stateful("Input")); // 先校验方法确实被调用了一次 verify(operation).doOperation(any(Stateful.class)); // 校验调用时的参数状态和预期一致 assertEquals(new Stateful("Input"), capturedCallInput.get()); }
多调用场景适配
如果需要校验同一个mock方法被多次调用的参数状态,只需要把AtomicReference换成List存储多个快照即可:
List<Stateful> capturedInputs = new ArrayList<>(); when(operation.doOperation(any(Stateful.class))).thenAnswer(invocation -> { Stateful input = invocation.getArgument(0); capturedInputs.add(new Stateful(input.getValue())); return null; }); // 后续校验list里的元素顺序和状态即可
内容的提问来源于stack exchange,提问作者M. Justin
相关产品推荐
相关产品推荐

