我正在尝试为此编写一个单元测试:
try (final DatagramChannel channel = helper.createChannel()) {
...
}在我的测试中,我模拟了助手(使用Mockito),并告诉helper.createChannel()返回一个模拟的通道。
此测试失败,出现以下错误
java.lang.NullPointerException
at java.nio.channels.spi.AbstractInterruptibleChannel.close(AbstractInterruptibleChannel.java:111)我知道Java中的try-with-resources工具在退出try块时调用DatagramChannel中的close()方法,但是不应该调用模拟的DatagramChannel中的close()方法吗?
调试器告诉我AbstractInterruptibleChannel中的closeLock为空。
我应该继承DatagramChannel的子类,覆盖其中的close()方法,然后模拟我的子类吗?或者,我以更深刻的方式做错了什么( helper mock返回一个mock)?
问候,弗雷德里克·伊斯雷森
测试代码,根据请求:
@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");
}如您所见,我没有为channel.close()指定任何行为。我相信我不应该这样做,因为close()返回void。
发布于 2013-02-28 21:36:25
您正在模拟一个扩展AbstractInterruptibleChannel的真实类DatagramChannel。然而,AbstractInterruptibleChannel.close是最终的,而Mockito目前不能模拟最终的代码。这就解释了为什么你在代码中有一个NPE。
我必须提醒您,人们普遍认为,模仿您不拥有的类型是一种糟糕的做法。我见过人们这样做,几年后,当真正的实现发生变化时,他们会有糟糕的惊喜,但模拟行为并没有,所以当他们更新库的版本时,他们错误地认为一切都是正常的。
但是,如果您想继续这种方式,因为您有充分的理由(确实有一些),您可以返回一个模拟的接口,比如实际上扩展了Closeable的Channel。或者,您可以使用DatagramChannel中提供的任何其他需要与之交互的接口。另外,如果需要多个接口,只需使用mock(Channel.class, withSetting().extraInterfaces(...))即可。
希望这能帮你干杯,Brice
发布于 2017-11-22 06:00:08
我也遇到了同样的问题,使用spy(..)代替mock(..)对我很管用。我试图在截断文件时模拟一个错误,我的系统正在相应地处理该错误。
FileChannel fileChannel = spy(FileChannel.class);
mockStatic(FileChannel.class);
when(FileChannel.open(eq(filePath), eq(StandardOpenOption.WRITE))).thenReturn(fileChannel);
when(fileChannel.truncate(1000L)).thenThrow(new IOException("Unable to truncate file"));
...
// Snippet being tested!
fileChannel = FileChannel.open(filePath, StandardOpenOption.WRITE);
fileChannel.truncate(1000L); // Will throw the exception!发布于 2015-02-10 13:19:00
抛开您是否应该这样做不谈,解决此问题的一种方法是“修复”AbstractInterruptibleChannel模拟实例(无论是FileChannel、DatagramChannel等)。通过为用于同步close调用的closeLock字段提供对象。
private static void fixChannelMock(AbstractInterruptibleChannel mockFileChannel) throws Exception {
Field closeLockField = AbstractInterruptibleChannel.class.getDeclaredField("closeLock");
closeLockField.setAccessible(true);
closeLockField.set(mockFileChannel, new Object());
}尽管AbstractInterruptibleChannel的内部实现可能会发生变化,但要准备好在Java小版本上修复上面的代码。
https://stackoverflow.com/questions/15131105
复制相似问题