如何在JUnit+Mockito中仅Mock MyClass调用的Problematic构造方法?
仅Mock指定调用方的Problematic构造方法解决方案
针对你的需求,Mockito 5.5.0提供的MockedConstruction可以通过过滤逻辑精准控制哪些构造调用被Mock,完全满足"第三方库构造保留原行为、MyClass构造Mock"的约束。以下是两种可行方案:
方案1:通过构造参数过滤(简单直接)
如果MyClass和第三方库传入的构造参数唯一,可直接通过参数匹配来拦截目标构造调用:
class MockProblematicObjectConstructionTest { @Test void testMyClassProblematicMock() { try (MockedConstruction<Problematic> mockedProblematic = mockConstruction( Problematic.class, // 仅拦截参数为"this needs to be mocked"的构造调用 context -> "this needs to be mocked".equals(context.arguments().get(0)), (mock, context) -> { // 为Mock实例设置自定义行为,比如抛出异常 Mockito.doThrow(new RuntimeException("Mocked construction failure")).when(mock); })) { MyClass.myCode(); // 验证MyClass触发的构造被Mock(仅1个Mock实例) assertEquals(1, mockedProblematic.constructed().size()); // 第三方库的构造会执行真实逻辑,控制台会输出"Problematic object constructed: this is fine" } } }
核心逻辑
- 使用
mockConstruction的重载方法,传入Predicate<Context>作为过滤条件:返回true则Mock该构造,返回false则执行真实构造。 - 第三方库传入的参数是
"this is fine",过滤条件不匹配,因此保留原构造逻辑;MyClass的参数匹配,触发Mock行为。
方案2:通过调用栈过滤(更可靠)
如果构造参数可能重复,可通过调用栈判断构造调用的发起者,精准定位MyClass触发的构造:
class MockProblematicObjectConstructionTest { @Test void testMyClassProblematicMockByCaller() { try (MockedConstruction<Problematic> mockedProblematic = mockConstruction( Problematic.class, // 过滤调用栈中包含MyClass.myCode的构造调用 context -> { for (StackTraceElement element : Thread.currentThread().getStackTrace()) { if ("MyClass".equals(element.getClassName()) && "myCode".equals(element.getMethodName())) { return true; } } return false; }, (mock, context) -> { // 设置Mock行为,比如抛出异常 Mockito.doThrow(new RuntimeException("Mocked construction failure")).when(mock); })) { MyClass.myCode(); // 验证Mock实例数量 assertEquals(1, mockedProblematic.constructed().size()); } } }
核心逻辑
- 遍历当前线程的调用栈,检查是否存在
MyClass.myCode的调用记录,以此判断构造发起者。 - 仅对
MyClass触发的构造进行Mock,完全不影响第三方库的构造逻辑。
关键注意事项
- 两种方案均满足你的约束:第三方库的
Problematic实例保持真实构造,MyClass的实例可自定义Mock行为(如抛异常)。 - 方案1性能更优,适合参数唯一的场景;方案2不依赖参数,适用于复杂的调用场景。
内容的提问来源于stack exchange,提问作者Danilo Piazzalunga
相关产品推荐
相关产品推荐

