在查看我的代码覆盖率时,我注意到很多单元测试无法检查最终块,这些块试图关闭finally块中的打开InputStreams.
一个示例摘录是:
try { f = new BufferedInputStream(new FileInputStream(source)); f.read(buffer); } finally { if (f != null) try { f.close(); } catch (IOException ignored) { } } }
有没有适当的解决方案来使用JUnit4检查finally块内的所有内容?
我知道在保持最高生产力的同时,无法实现100%的代码覆盖率.然而,这些红线在报告中引人注目.
解决方法
首先考虑使用
IOUtils.closeQuietly()
,它会将未经测试的代码(可能是重复代码)减少为:
try { f = new BufferedInputStream(new FileInputStream(source)); f.read(buffer); } finally { IoUtils.closeQuietly(f); }
现在变得艰难. “正确”的方法是将BufferedInputStream的创建外部化到另一个类中并注入mock.有了一个模拟,你可以验证是否调用了适当的close()方法.
@ JeffFoster的答案非常接近我的意思,但是我会推荐组合而不是继承(以更多的代码为代价):
try { f = fileSystem.open(source); f.read(buffer); } finally { IoUtils.closeQuietly(f); }
其中fileSystem是FileSystem接口的一个实例,其中简单的实际实现在生产代码中注入或模拟用于测试.
interface FileSystem { InputStream open(String file); }
外部化文件打开的另一个好处是,如果您决定删除缓冲或添加加密,则只需要修改一个位置.
使用该接口,您可以使用模拟实例化测试代码(使用Mockito):
//given FileSystem fileSystemMock = mock(FileSystem.class); InputStream streamMock = mock(InputStream.class); given(fileSystemMock.open("file.txt")).willReturn(streamMock); //when //your code //then verify(streamMock).close();