如何正确监视输入流

swa*_*ter 6 java mockito spy junit5

我的理解是,它将Mockito.spy(object)代理包装在现有对象周围。该代理将方法调用委托给监视对象并允许进一步验证(因此它与不提供实现的模拟不同)。

我想监视输入流以确保正确调用关闭/读取方法。但以下(简单)间谍代码不起作用:

// Create a spy input stream object
String testData = "Hello";
InputStream inputStream = new ByteArrayInputStream(testData.getBytes(StandardCharsets.UTF_8));
InputStream spiedInputStream = spy(inputStream);
assertEquals(testData.getBytes(StandardCharsets.UTF_8).length, spiedInputStream.available()); // Fails: Expected 5, Actual 0

// Read the input stream
byte [] readData = new byte[testData.length()];
assertEquals(testData.getBytes(StandardCharsets.UTF_8).length, spiedInputStream.read(readData)); // Fails: Expected 5, Actual -1
assertEquals(testData, new String(readData, StandardCharsets.UTF_8)); // Fails, readData is fully zeroed
Run Code Online (Sandbox Code Playgroud)

那么我做错了什么(Ubuntu 22.04,Java 17,Mockito 4.7.0)

Les*_*iak 2

您所描述的行为只能在以下配置上重现:

  • Mockito核心
  • JDK 17+

最简单的方法是切换到mockito-inline。

对于mockito-core和JDK 17,spy中的字段未正确初始化:

public ByteArrayInputStream(byte buf[]) {
    this.buf = buf;
    this.pos = 0;
    this.count = buf.length;
}
Run Code Online (Sandbox Code Playgroud)

count 变量应该等于 buf.length,但在间谍中它被设置为 0。

这个问题源于子类模拟制作器从根本上限制在 JDK17 上,mockito 团队似乎意识到了这个问题,甚至考虑在 JDK 17 上默认切换到内联模拟制作器:

在 JDK 17+ 上将默认的mockmaker切换为内联mockmaker#2589

TLDR:越来越多的用例(默认情况下)在 Mockito 和 JDK 17 中被破坏。这是因为子类 mockmaker 遇到了 JDK 17 的基本限制,但内联 mockmaker 可以按预期工作。