如何在JUnit Mockito中验证并捕获InputStream的内容?
解决方案
你遇到的问题核心是:try-with-resources会在commandRunner.run()执行完成后立刻关闭输入流,导致Mockito捕获到的流对象在验证阶段已经处于关闭状态,无法读取内容。解决的关键是在流仍处于打开状态时(即run方法执行过程中)读取并保存流的内容,而非等到流关闭后再操作流对象。
下面是两种可行的实现方式:
方式一:使用Mockito Answer暂存流内容
通过doAnswer定义mock对象的行为,在commandRunner.run()被调用的瞬间读取输入流内容并暂存,后续再验证内容是否符合预期:
@Test public void testHappyPath() throws IOException { ClassLoader classLoader = this.getClass().getClassLoader(); File file = new File(classLoader.getResource("MyTestInputFile.txt").getFile()); // 预先读取预期的文件内容 byte[] expectedContent = Files.readAllBytes(file.toPath()); AtomicReference<byte[]> actualContent = new AtomicReference<>(); // 定义mock的run方法行为:读取输入流内容并暂存 doAnswer(invocation -> { InputStream inputStream = invocation.getArgument(1); actualContent.set(inputStream.readAllBytes()); return null; }).when(commandRunner).run(anyString(), any(InputStream.class)); // 执行被测方法 commandRunnerInputFile.run("MyApplication.exe", file); // 验证方法调用及内容匹配 verify(commandRunner).run(eq("MyApplication.exe"), any(InputStream.class)); assertArrayEquals(expectedContent, actualContent.get()); // 验证第一个字符为'c' assertEquals('c', (char) actualContent.get()[0]); }
方式二:直接在Answer中完成内容验证
如果不需要暂存内容,也可以在Answer内部直接完成断言,省去后续的变量验证步骤:
@Test public void testHappyPath() throws IOException { ClassLoader classLoader = this.getClass().getClassLoader(); File file = new File(classLoader.getResource("MyTestInputFile.txt").getFile()); String expectedContent = Files.readString(file.toPath()); // 调用run方法时直接读取流内容并断言 doAnswer(invocation -> { InputStream is = invocation.getArgument(1); String actualContent = new String(is.readAllBytes()); assertEquals(expectedContent, actualContent); return null; }).when(commandRunner).run(eq("MyApplication.exe"), any(InputStream.class)); commandRunnerInputFile.run("MyApplication.exe", file); // 确保方法确实被调用 verify(commandRunner).run(eq("MyApplication.exe"), any(InputStream.class)); }
注意事项
- Java 9及以上支持
InputStream.readAllBytes()方法,若使用Java 8,可借助IOUtils.toByteArray(is)(Apache Commons IO工具类)或手动实现流读取逻辑。 - 禁止捕获
InputStream对象后在验证阶段读取内容,此时流已被try-with-resources自动关闭,必然抛出流关闭异常。
内容的提问来源于stack exchange,提问作者davidemm
相关产品推荐
相关产品推荐

