在 Mockito 单元测试中不应 mock close() 方法,因为会破坏 try-with-resources 的真实资源管理,导致资源泄漏、测试失真或 NPE;应优先使用 ByteArrayInputStream、ByteArrayOutputStream 等真实内存流,并通过 spy 或 doThrow 验证 close() 行为。

在 Mockito 单元测试中,不能也不应该直接 mock close() 方法来干扰 try-with-resources 的资源释放逻辑。try-with-resources 依赖的是真实资源的生命周期管理,mocking close() 不仅违背设计初衷,还容易导致资源泄漏、测试失真或 `NullPointerException` 等问题。
为什么不要 mock close() 方法
try-with-resources 编译后会自动生成 finally 块调用 close(),该调用发生在资源对象本身上。如果用 Mockito mock 一个实现了 AutoCloseable 的对象(比如 InputStream),默认情况下 mock 对象的 close() 是空实现 —— 这看似“成功”,但会掩盖真实行为,且无法验证是否被调用(除非显式 stub)。更重要的是:
• 资源未真正关闭 → 可能影响后续测试(如文件句柄占用)
• 无法测试异常路径(如 close() 抛出异常时的 suppressed exception 处理)
• 真实流的行为(如缓冲、状态变更)完全丢失,测试失去意义
推荐做法:使用真实资源 + 内存模拟
对 I/O 流类,优先使用 JDK 提供的轻量级内存实现,它们行为真实、线程安全、无需 cleanup:
-
输入流:用
new ByteArrayInputStream(new byte[]{...})或new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8)) -
输出流:用
ByteArrayOutputStream,结束后可调用toByteArray()或toString()断言内容 -
Reader/Writer:用
StringReader/StringWriter,简单可靠
这些对象的 close() 是安全的空操作或仅清理内部引用,配合 try-with-resources 完全符合预期,且能覆盖正常和异常分支(例如手动抛出 IOException 测试错误处理)。
立即学习“Java免费学习笔记(深入)”;
需要验证 close() 是否被调用?用 doThrow + 验证
如果业务逻辑明确要求检查 close() 调用(如包装器类、连接池回收逻辑),可结合 Mockito.spy() 或真实对象 + doAnswer() 捕获调用:
- 对真实流(如
ByteArrayInputStream)使用spy(),然后verify(mockedStream).close() - 若必须 mock,用
doAnswer(invocation -> { /* 记录调用 */ return null; }).when(mockStream).close();,再验证记录 - 测试
close()异常场景:用doThrow(new IOException("boom")).when(mockStream).close();,再断言主异常是否包含 suppressed exception
避免陷阱:不 mock AutoCloseable 接口本身
不要写 @Mock Closeable mockCloseable 并注入到被测方法中——这会让 try-with-resources 关闭一个“假”资源,而真实资源(如文件、Socket)根本没参与。正确方式是:
• 被测类应接受抽象类型(如 InputStream),构造/方法注入时传入内存流
• 若被测类内部 new 出流,考虑将其抽取为可注入的工厂或 supplier,便于替换


















