如何正确模拟自动关闭资源?

Fre*_*son 5 java mockito

我正在尝试为此编写单元测试:

try (final DatagramChannel channel = helper.createChannel()) {

...

}
Run Code Online (Sandbox Code Playgroud)

在我的测试中,我模拟了帮助器(使用Mockito),并告诉helper.createChannel()返回一个模拟通道.

此测试失败了

java.lang.NullPointerException
at java.nio.channels.spi.AbstractInterruptibleChannel.close(AbstractInterruptibleChannel.java:111)
Run Code Online (Sandbox Code Playgroud)

我知道Java中的try-with-resources工具在退出try块时调用DatagramChannel中的close()方法,但是不应该调用模拟的DatagramChannel中的close()方法吗?

调试器告诉我AbstractInterruptibleChannel中的closeLock为null.

我应该继承DatagramChannel,重写其中的close()方法,然后模拟我的子类吗?或者,我是否以更深刻的方式做错了(帮助器模拟返回模拟)?

此致Fredrik Israelsson

测试代码,根据要求:

@Mock
private InetAddress peerAddress;
@Mock
private UDPChannelHelper helper;
@Mock
private DatagramChannel channel;

private UDPTransportImpl transport;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
    when(helper.createChannel()).thenReturn(channel);
    transport = new UDPTransportImpl(peerAddress, 0, helper);
}

@Test
public void testNormalSubmit() throws Exception {
    transport.submit("Hello");
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我没有为channel.close()指定任何行为.我相信我不应该,因为close()返回void.

Bri*_*ice 7

你正在嘲笑一个真正的阶级DatagramChannel,而且还在延伸AbstractInterruptibleChannel.然而,这AbstractInterruptibleChannel.close是最终的,Mockito目前无法模拟最终代码.这解释了为什么你的代码中有NPE.

我必须提醒你,人们普遍认为你不拥有的嘲弄类型是不好的做法.我已经看到人们这样做,多年后当真正的实现发生了变化时他们就有了不好的惊喜,但是模拟行为没有,所以当他们更新库的版本时,他们错误地认为一切都没问题.

仍然如果你想继续这种方式,因为你有正当理由(并且有一些),你可以返回一个接口的模拟,就像Channel实际扩展Closeable.或者您可以使用您需要与之交互的任何其他界面DatagramChannel.此外,如果您需要多个接口,请使用mock(Channel.class, withSetting().extraInterfaces(...)).

希望有助于干杯,布里斯