Unit testing is finally blocked in Java 6

While looking at my code, I noticed that many Unit tests failed to finally check the blocks that try to close open InputStreams in finally blocks.

One example excerpt:

try { f = new BufferedInputStream(new FileInputStream(source)); f.read(buffer); } finally { if (f != null) try { f.close(); } catch (IOException ignored) { } } } 

Is there a suitable solution for checking everything inside the finally block with JUnit4?

I know that 100% code coverage is unattainable while maintaining maximum performance. However, these red lines are a kind of eyecatcher in the report.

+7
source share
4 answers

First of all, consider using IOUtils.closeQuietly() , which will reduce your unverified code (and probably duplication) by:

  try { f = new BufferedInputStream(new FileInputStream(source)); f.read(buffer); } finally { IOUtils.closeQuietly(f); } 

Now it’s getting hard. The “right” way is to externalize the creation of the BufferedInputStream in another class and introduce the layout. With the layout, you can check if the appropriate close() method was involved.

@JeffFoster's answer is pretty close to what I mean, however I would recommend composition over inheritance (due to more code):

  try { f = fileSystem.open(source); f.read(buffer); } finally { IOUtils.closeQuietly(f); } 

Where fileSystem is an instance of the fileSystem interface with a simple real implementation introduced into production code or layout for testing.

 interface FileSystem { InputStream open(String file); } 

Another advantage of external file disclosure is that if you decide to remove buffering or add encryption, there is only one place to change.

Using this interface, you create test code using mocks (using 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(); 
+6
source

You can reorganize the code a bit

 public class TestMe { public void doSomething() { try { f = new BufferedInputStream(new FileInputStream(source)); f.read(buffer); } finally { if (f != null) try { f.close(); } catch (IOException ignored) { } } } } 

Something like that

 public class TestMe { public void doSomething() { try { f = createStream() f.read(buffer); } finally { if (f != null) try { f.close(); } catch (IOException ignored) { } } } public InputStream createStream() { return new BufferedInputStream(new FileInputStream(source)); } } 

And now you can write your test to capture the class of the input stream and verify that it is closed. (the code is rude, but I hope you get a general idea).

 public void TestSomething () { InputStream foo = mock(InputStream.class); // mock object TestMe testMe = new TestMe() { @Override public InputStream createStream() { return foo; } } testMe.something(); verify(foo.close()); } 

Whether it's worth it or not, that's another question!

+5
source

You must enter the mocked BufferedInputStream — or create one using factory — and when the mock close() method is called, then IOException .

In addition, I will not have the finally block above until you find any logic there.

0
source

I think you need to ask yourself if this is really worth the testing effort. Some testing addicts tend to skip the diminishing returns from trying to achieve 100% test coverage. In this case, it seems that some of the proposed solutions complicate the real code to make it “verifiable”. I'm fine with a complex test code, but adding complexity to the real code just to make it “testable” strikes me as a terrible idea.

0
source

All Articles