
本文介绍在不修改原有代码结构的前提下,使用 Mockito 3.5+ 的 mockConstruction 特性,对 Class1 中循环创建 Class2 实例并调用其方法的行为进行精确验证。
本文介绍在不修改原有代码结构的前提下,使用 mockito 3.5+ 的 mockconstruction 特性,对 class1 中循环创建 class2 实例并调用其方法的行为进行精确验证。
在单元测试中,当被测类(如 Class1)直接通过 new 关键字构造依赖对象(如 Class2),且无法通过依赖注入等方式解耦时,传统 Mockito 的 @Spy 或 @Mock 无法拦截构造过程——因为 spy 只作用于已有实例,而 new Class2(...) 每次都生成全新、未被代理的对象。
幸运的是,自 Mockito 3.5.0 起,官方正式支持 构造过程模拟(Mocked Construction),可通过 mockConstruction(Class<t>)</t> 拦截指定类的所有构造调用,并为每次构造返回一个受控的 mock 实例。这正是解决本场景的理想方案。
以下是一个完整、可运行的测试示例:
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mockConstruction;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
class Class1Test {
@Test
void myMethod_createClass2PerItemAndCall_anotherMethod() {
// 拦截 Class2 的所有构造调用,每次构造后自动 mock 其实例
try (MockedConstruction<Class2> mocked = mockConstruction(Class2.class,
(mock, context) -> {
// 可选:预设构造参数相关行为(需 Class2 提供访问 element 的方法)
when(mock.getElement()).thenReturn((String) context.arguments().get(0));
})) {
Class1 class1 = new Class1();
class1.myMethod(Arrays.asList("a", "b", "c")); // 触发 3 次 Class2 构造
// 断言:共构造了 3 个 Class2 实例
List<Class2> instances = mocked.constructed();
assertEquals(3, instances.size());
// 验证每个实例的构造参数(需 Class2 添加 package-private 或 public 的 getElement())
assertEquals("a", instances.get(0).getElement());
assertEquals("b", instances.get(1).getElement());
assertEquals("c", instances.get(2).getElement());
// 验证 each instance's anotherMethod was called exactly once
verify(instances.get(0)).anotherMethod();
verify(instances.get(1)).anotherMethod();
verify(instances.get(2)).anotherMethod();
}
}
}? 关键前提与注意事项:
-
mockConstruction是 静态资源型 API,必须配合try-with-resources使用,确保构造监控在测试结束后自动清理; -
Class2需暴露构造参数用于断言(如添加String getElement()方法),否则无法验证“是否按预期参数构造”;该方法可设为package-private,无需对外暴露; -
mockConstruction仅适用于 非 final 类(Class2不能是 final);若Class2为 final,需启用 ByteBuddy(Mockito 默认已集成)且确保 JVM 允许运行时字节码增强; - 此方案是“不可重构场景下的务实选择”,长期仍建议通过依赖倒置(如引入
Class2Factory)提升可测性与设计质量。
综上,mockConstruction 提供了一种简洁、类型安全且无需 PowerMock 等额外依赖的方式,在 Java 11 + Mockito 3.5 环境下精准验证对象构造频次与行为链路,是现代 Mockito 测试实践的重要进阶能力。

















