为什么 Mockito 对 InputStreams 的行为很奇怪?

Why is Mockito behaving weird with InputStreams?

在调试时,我在使用 Mockito 1.10 时遇到了一些非常奇怪的事情。我希望有人能解释这里的行为:

当我 运行 以下内容时,我的线程挂起并且我的测试从不 returns。 CPU 创建的 Java 进程也达到了天文数字!

@Test(expected = IOException.class)
public void mockitoWeirdness() throws IOException {
    final InputStream mis = mock(InputStream.class);
    doThrow(IOException.class).when(mis).read();
    ByteStreams.copy(mis, new ByteArrayOutputStream());
}

当我如下手动存根这个方法时,抛出了预期的 IOException:

@Test(expected = IOException.class)
public void nonMockitoExpected() throws IOException {
    final InputStream mis = new InputStream() {

        @Override
        public int read() throws IOException {
            throw new IOException();
        }
    };
    ByteStreams.copy(mis, new ByteArrayOutputStream());
}

如果能帮助理解 mockito 方法失败的方式和原因,那就太棒了。

如果您查看 ByteStreams 实现,您会发现使用了 read(buf) 方法。 在您的情况下,它 returns null 因为没有针对它的模拟定义,这会导致 copy 方法中出现无限循环。

您可以更改 default mock behaviour 或手动添加 read(buff) 方法的定义。

你需要设置你的 mock 来调用 InputStream 的真正方法,当你还没有存根时

final InputStream mis = Mockito.mock(InputStream.class, Mockito.CALLS_REAL_METHODS);

javadoc

This implementation can be helpful when working with legacy code. When this implementation is used, unstubbed methods will delegate to the real implementation. This is a way to create a partial mock object that calls real methods by default.

默认情况下,Mockito 模拟所有内容。您首先使用的 ByteStreams#copy 方法调用 InputStream#read(byte[])。由于 mockito 已经嘲笑了它,它将 return 0 ByteStreams#copy 解释为 "there is more to read from this stream" 并继续阅读(无限循环)。

通过使用 Mockito.CALLS_REAL_METHODS,您告诉 Mockito 调用 InputStream 中的实际实现,它将委托给 read(),您已将其存根以抛出异常。