Search code examples
javaexceptionjunit4java-6try-catch-finally

Unit testing finally blocks in Java 6


While reviewing my code coverage i noticed a lot of Unit tests fail to check finally blocks which try to close open InputStreams in finally blocks.

One Example excerpt is:

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

Is there any appropriate solution to check everything inside the finally block using JUnit4 ?

I know that a code coverage of 100% is not achievable while keeping maximum productivity in mind. However these red lines are sort of an eyecatcher in the report.


Solution

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

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

    Now it becomes hard. The "right" way would be to externalize the creation of BufferedInputStream into another class and inject mock. Having a mock you can verify whether appropriate close() method was invoked.

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

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

    Where fileSystem is an instance of FileSystem interface with simple real implementation injected in production code or mock for testing.

    interface FileSystem {
    
        InputStream open(String file);
    
    }
    

    Another benefit of externalizing file opening is that if you one decide to remove buffering or add encryption, there is just a single place to modify.

    Having that interface you instantiate your test code with 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();