Mockito 3.5+替代PowerMockito的whenNew功能实现问题
从PowerMockito的whenNew迁移到Mockito 3.5+的解决方案
针对你迁移时遇到的两个问题,直接给出具体实现方案:
问题1:替换内部创建的ArrayList为外部实例
Mockito的mockConstruction支持通过自定义Answer控制构造时返回的对象,直接返回你外部创建的实例即可实现原whenNew的替换逻辑。
示例代码:
// 外部创建你要指定的ArrayList实例 List<String> targetList = new ArrayList<>(); targetList.add("init-item"); // 在try-with-resources块内拦截ArrayList的构造(仅块内生效) try (MockedConstruction<ArrayList> mockedList = mockConstruction(ArrayList.class, (context, settings) -> targetList)) { // 执行被测方法 someService.doStuff(); // 验证外部实例的变化,比如检查是否新增了预期元素 assertThat(targetList).contains("expected-new-item"); }
问题2:解决mockConstruction默认不调用真实构造导致的NPE
默认情况下mockConstruction会创建空壳mock对象,不执行真实构造逻辑。要调用真实构造并保留实例正常功能,有两种方式:
方式1:返回真实实例
直接在Answer中调用类的真实构造方法,返回真实对象:
try (MockedConstruction<ArrayList> mockedList = mockConstruction(ArrayList.class, (context, settings) -> new ArrayList<>())) { someService.doStuff(); // 获取内部创建的真实实例并验证 ArrayList<String> constructedList = mockedList.constructed().get(0); assertThat(constructedList).hasSize(2); }
方式2:返回Spy实例(兼顾真实方法调用和行为验证)
如果需要同时验证实例的方法调用(比如add方法被调用次数),可以返回spy包装的真实实例:
try (MockedConstruction<ArrayList> mockedList = mockConstruction(ArrayList.class, (context, settings) -> { ArrayList<String> realList = new ArrayList<>(); return spy(realList); // 用spy包装真实实例 })) { someService.doStuff(); ArrayList<String> constructedSpy = mockedList.constructed().get(0); // 验证方法调用行为 verify(constructedSpy, times(2)).add(anyString()); // 验证真实数据 assertThat(constructedSpy).containsAll(List.of("a", "b")); }
关键区别说明
和PowerMockito的whenNew全局拦截不同,Mockito的mockConstruction通过try-with-resources实现作用域控制,避免全局mock带来的测试污染,更符合现代测试的隔离原则。
内容的提问来源于stack exchange,提问作者Jovan Perovic
相关产品推荐
相关产品推荐

