如何用Mockito 4.5 Mock构造函数内创建的Child字段并注入Parent
解决Mockito 4.5中Mock构造函数内new出的Child对象问题
直接用Mockito 4.5提供的MockedConstruction就能解决这个问题——它可以拦截Child类的构造调用,自动把构造出来的实例替换成mock对象,不需要手动注入到Parent里。具体实现步骤如下:
1. 依赖准备(以JUnit5为例)
确保测试依赖包含Mockito的JUnit5扩展:
<!-- Maven依赖示例 --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>4.5.1</version> <scope>test</scope> </dependency>
2. 编写测试代码
在测试方法中,用MockedConstruction包裹Parent的实例化逻辑,同时指定Child的mock行为:
import org.junit.jupiter.api.Test; import org.mockito.MockedConstruction; import static org.mockito.Mockito.*; public class ParentTest { @Test void testThanksGivingVisit() { // 1. 准备测试依赖的mock对象 Legacy mockLegacy = mock(Legacy.class); Config mockConfig = mock(Config.class); // 模拟config.getBirthCertificate()的返回值(按需配置) when(mockConfig.getBirthCertificate()).thenReturn("fake-cert-id"); // 2. 用MockedConstruction拦截Child构造,生成mock实例并配置行为 try (MockedConstruction<Child> mockedChild = mockConstruction(Child.class, (mock, context) -> { // 指定withDrawFromBackAccount的返回值,避免触发DB操作 when(mock.withDrawFromBackAccount()).thenReturn(200); })) { // 3. 实例化Parent——此时构造函数里new的Child是mock对象 Parent parent = new Parent(mockLegacy, mockConfig); // 4. 调用待测试方法 Result result = parent.thanksGivingVisit(); // 5. 编写业务断言(根据你的Result逻辑调整) // 示例:assertEquals(预期值, result.getAmount()); // 可选:验证Child的方法是否被调用 Child childMock = mockedChild.constructed().get(0); verify(childMock, times(1)).withDrawFromBackAccount(); } } }
关键原理说明
MockedConstruction会在它的作用域(try-with-resources块内)拦截所有Child类的构造调用,返回预先配置好的mock对象。- 当你在块内实例化
Parent时,Parent构造函数里new Child(...)的调用会被Mockito自动拦截,生成的child字段就是mock实例,完全不需要额外的注入操作。 - try-with-resources语法会自动关闭
MockedConstruction,避免该mock行为影响其他测试用例。
注意事项
- 如果不需要配置mock的行为,可以简化为
mockConstruction(Child.class),此时mock方法会返回对应类型的默认值(比如int类型返回0)。 - 务必确保
MockedConstruction的作用域包裹住所有会创建Child实例的代码,否则拦截会失效。
内容的提问来源于stack exchange,提问作者Dreamer
相关产品推荐
相关产品推荐

