如何用Mockito Spy验证Class1中Class2实例创建及方法调用
解决方案
因为原代码中Class1直接在myMethod内部实例化Class2,Mockito默认无法拦截构造函数调用(且你无法修改POM引入PowerMock这类工具),所以我们可以通过微调Class1的代码,将Class2的创建逻辑抽成可覆盖的方法,再结合Mockito Spy来实现验证需求。
步骤1:调整Class1代码
把创建Class2的逻辑提取为一个非私有方法(比如protected权限),这样Spy对象可以覆盖这个方法:
public class Class1 { public Class1(){} public void myMethod(List<String> list){ for (String element: list){ Class2 class2 = createClass2(element); // 替换直接new的逻辑 class2.anotherMethod(); } } // 提取出来的创建方法,供Spy拦截 protected Class2 createClass2(String element) { return new Class2(element); } }
步骤2:编写测试用例
通过SpyClass1,拦截createClass2方法返回Mock的Class2实例,以此验证每个列表元素对应一次实例创建,且anotherMethod被执行:
import org.junit.Test; import org.mockito.Mockito; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Class1Test { @Test public void myMethod_CreatesClass2ForEachElementAndCallsAnotherMethod() { // 测试数据:3个元素的列表 List<String> testElements = Arrays.asList("foo", "bar", "baz"); List<Class2> class2Mocks = new ArrayList<>(); // 创建Class1的Spy对象 Class1 class1Spy = Mockito.spy(new Class1()); // 拦截createClass2方法,每次调用返回一个Mock的Class2并收集起来 Mockito.doAnswer(invocation -> { Class2 mockClass2 = Mockito.mock(Class2.class); class2Mocks.add(mockClass2); return mockClass2; }).when(class1Spy).createClass2(Mockito.anyString()); // 执行待测试方法 class1Spy.myMethod(testElements); // 验证1:createClass2被调用的次数等于列表元素数量 Mockito.verify(class1Spy, Mockito.times(testElements.size())) .createClass2(Mockito.anyString()); // 验证2:每个Mock的Class2实例都调用了anotherMethod for (Class2 mock : class2Mocks) { Mockito.verify(mock).anotherMethod(); } // 可选:验证每个createClass2调用的参数和列表元素一致 Mockito.verify(class1Spy).createClass2("foo"); Mockito.verify(class1Spy).createClass2("bar"); Mockito.verify(class1Spy).createClass2("baz"); } }
原理说明
- 提取
createClass2方法后,我们可以通过Spy对象覆盖这个方法的行为,替换为返回Mock实例,避免真正创建Class2对象。 - 收集所有Mock的
Class2实例后,就能直接验证每个实例的anotherMethod是否被调用。 - 同时通过
verify方法确认createClass2的调用次数和参数,确保每个列表元素都对应一次Class2的创建。
内容的提问来源于stack exchange,提问作者ebarbara
相关产品推荐
相关产品推荐

