如何在JUnit Mockito中验证和捕获InputStream的内容?

qxgroojn  于 2023-04-20  发布在  其他
关注(0)|答案(1)|浏览(228)

我有以下设置:

public interface CommandRunner
{
    void run(String cmd, InputStream is) throws IOException;
}

public class CommandRunnerInputFile
{
  private final CommandRunner commandRunner;
  
  public CommandRunnerInputFile(CommandRunner commandRunner) {
    this.commandRunner = commandRunner;
  }
  
  public void run(String command, File inputFile) throws IOException {
    try (FileInputStream is = new FileInputStream(inputFile)) {
      this.commandRunner.run(command, is);
    }
  }

}

@ExtendWith(MockitoExtension.class)
public class TestCommandRunnerInputFile
{
  @Mock CommandRunner commandRunner;
  
  @Captor ArgumentCaptor<InputStream> inputStream;

  
  private CommandRunnerInputFile commandRunnerInputFile;

  @BeforeEach
  void initService() {
    commandRunnerInputFile = new CommandRunnerInputFile(commandRunner);
  }
  
  @Test
  public void testHappyPath() throws IOException {
    ClassLoader classLoader = this.getClass().getClassLoader();
    File file = new File(classLoader.getResource("MyTestInputFile.txt").getFile());

    commandRunnerInputFile .run("MyApplication.exe", file);
    
    verify(commandRunner).run(eq("MyApplication.exe"), inputStream.capture());
    assertEquals('c', (char)inputStream.getValue().read());
  }
}

当我运行这个测试时,它失败了,并出现以下异常:

java.io.IOException: Stream Closed
    at java.io.FileInputStream.read0(Native Method)
    at java.io.FileInputStream.read(FileInputStream.java:207)

这对我来说是有意义的,因为在执行方法的过程中,底层的FileInputStream在完成执行时是关闭的。也就是说,在FileInputStream被Mockito捕获的时间点,它是打开的。但等我确认通过了(并尝试验证其内容)它是关闭的。我能做什么不是简单地捕获InputStream对象本身,而是实际捕获其内容以进行验证?

fykwrbwg

fykwrbwg1#

ArgumentCaptor在这里没有帮助,因为Stream很可能已经被关闭了,例如从try-with-resources。所以你必须在测试期间用mock捕获内容:

final StringBuilder actualContent = new StringBuilder();
when(myMock.doSomethingWithAnInputStream(any()).thenAnswer(invocation -> {
    final InputStream is = invocation.getArgument(0); 
    actualContent.append(CharStreams.toString(new InputStreamReader(is, StandardCharsets.UTF_8)));
    return path;
  });

// ... run your tests ...

verify(myMock).doSomethingWithAnInputStream(any()); // can be omitted if only one arg
assertEquals("this should be in the stream", actualContent.toString());

当你的方法返回一个void时,mocking看起来有点不同:

doAnswer(invocation -> {
    final InputStream is = invocation.getArgument(1); 
    actualContent.append(CharStreams.toString(new InputStreamReader(is, StandardCharsets.UTF_8)));
    return null;
  }).when(commandRunner).run(anyString(), any());

我使用Guava来获取InputStream内容,但您也可以使用ApacheIOUtils或其他许多选项之一described here

相关问题