使用Mockito 3的mockConstruction对new File打桩报StackOverflowError如何解决
错误根因
你遇到的StackOverflowError是两个问题共同导致的:
- 无差别mock了JDK核心类
java.io.File的所有构造逻辑,而JDK类加载器、日志框架、Mockito本身的运行流程都会依赖File类的实例创建和核心方法调用。你设置了调用真实方法后,mock实例的方法调用会触发真实IO逻辑,进一步触发新的File构造,形成无限递归。 MockedConstruction的初始化回调用法错误:你在回调中返回MockSettings属于无效写法,MockInitializer接口本身无返回值,MockSettings需要作为单独参数传入mockConstruction方法。另外回调中的日志打印操作会触发日志框架的文件IO,进一步加剧递归。
正确实现方案
方案1:按需打桩(推荐)
如果不需要调用File的真实方法,仅需要对特定方法打桩,优先用该方案,完全避免递归风险:
try (MockedConstruction<File> mockedConstruction = Mockito.mockConstruction(File.class)) { // 代码块内所有通过new创建的File都是mock对象 File stub = new File("test"); // 按需打桩你需要的方法 Mockito.when(stub.exists()).thenReturn(true); Mockito.when(stub.getAbsolutePath()).thenReturn("/tmp/test"); // 执行业务逻辑 }
try-with-resources结束后会自动释放构造mock,不会影响其他代码的File实例创建。
方案2:需要调用真实方法的场景
如果确实需要调用File的真实逻辑,调整参数位置,且不要在初始化回调中做可能触发IO的操作:
try (MockedConstruction<File> ignored = Mockito.mockConstruction(File.class, // MockSettings作为第二个参数传入,配置默认调用真实方法 Mockito.withSettings().defaultAnswer(CALLS_REAL_METHODS), // 初始化回调作为第三个参数,无返回值,避免触发IO操作 (mock, context) -> { // 调试打印用System.out,不要用日志框架 System.out.printf("new file: count=%s, args=%s%n", context.getCount(), context.arguments()); })) { File stub = new File("test"); // 执行业务逻辑 }
注意事项
- 尽量不要对JDK核心IO类开启全局真实方法调用,确有需要时可以加构造参数匹配规则,仅拦截你业务代码中特定参数的
File构造,跳过JDK内部触发的构造。 - 不要在构造mock的初始化回调中执行任何可能触发文件IO、类加载的操作,避免触发递归。
内容的提问来源于stack exchange,提问作者Pop Shi
相关产品推荐
相关产品推荐

