Cause IOException to cover catch blocks

Viewed 329

I am trying to cover the catch blocks in the code below but I am unable to. I understand that I need to cause an IOException while reading/writing into a file but I am not able to. Also, I cannot use PowerMockito to cover static methods as I am using Junit5. Can anyone help?

 @Override
    public String execute(UploadCategoryImageCommandRequest request) {
        File tempFile = null;
        FileOutputStream fos = null;
        String fileName = "";
            fileName = UUID.randomUUID().toString() + System.currentTimeMillis() + ".svg";
            try {
                tempFile = File.createTempFile(fileName, "svg");
                fos = new FileOutputStream(tempFile);
                fos.write(request.getFile().getBytes());
            } catch (IOException e) {
                log.error("File Creation Error: {}", e);
                upload.setFileStatus(FileStatus.FAILED);
                uploadRepository.save(upload);
                throw new ApplicationException(ErrorKey.IMAGE_UPLOAD, ErrorCode.FAILED);
            }
                return string;
            
        }

This is one of the test case that i have written but it returns this error - org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'. For example: when(mock.getArticles()).thenReturn(articles);

Also, I am not sure if I should mock the File class in the below test case that I have written

 @Test
    public void exception() throws IOException {
        Upload upload = Upload.builder().fileStatus(FileStatus.FAILED).imagePath("http://").build();
        MockMultipartFile firstFile = new MockMultipartFile("fileName", "fileName.svg", "text/plain", "some xml".getBytes());
        UploadCategoryImageCommandRequest uploadCategoryImageCommandRequest = UploadCategoryImageCommandRequest.builder()
                .file(firstFile)
                .uploadType(UploadType.CATEGORY)
                .build();     
Mockito.when(file.createTempFile("filename","svg")).thenThrow(IOException.class);
        uploadCategoryImageCommand.execute(uploadCategoryImageCommandRequest);

    }
2 Answers

File.createTempFile creates a file in the default temporary directory, which you could override by setting the java.io.tmpdir system property. If you set it to some directory that does not exist, and the temp file creation will fail, and you'd get an IOException. Just make sure you restore it when you're done so you don't mess up the rest of your tests. JUnit Pioneer's SetSystemProperty provides an elegant way of doing this:

@Test
@SetSystemProperty(key = "java.io.tmpdir", value = "/no/such/dir")
public void exception() throws IOException {
    // Call your code
}

Static access is always a Problem not only in testing context, but there is becomes most obvious.

A solution could be to place the static access into a separate class in a non static method. This class would be "too simple to fail" and therefore it would be justified to have no Code Coverage for that. Inject an instance of this helper class as constructor parameter to your code under test. Then you can simply replace it with a mock throwing the desired exception in that particular test.


Can you explain this with an example? - Meg

The new class (not needing Unit Tests -> Coverage 0%)

    class TempFileCreator{
      File createTempFile(String baseName, String extension){
         return File.createTempFile(fileName, extension);
      }
    }

Changes in your code under test (CUT):

    class YourClass{
       private final TempFileCreator  tempFileCreator;

       YourClass(TempFileCreator  tempFileCreator 
            /* more constructor parameters? */
            /* update the Builder, may hold an instance of TempFileCreator as a constant */
       ){
         this.tempFileCreator = tempFileCreator;
       }

       @Override
        public Single<String> execute(UploadCategoryImageCommandRequest request) {
          // lots of your code
            try {
              // more of your code
              File tempfile = tempFileCreator.createTempFile(fileName, "svg");
              // tempfile.deleteOnExit(); would prevent the extra section in finally block...
              // more of your code          
            } catch (IOException e) {
              // the code to verify (coverage does not have a value as such...)
            }
          }
    }

Your test:

@Mock
TempFileCreator  tempFileCreator; // should be injected to your CUT like the other mocks...

@Test
public void exception() throws IOException {
   Mockito.doThrow(new IOException("this is a test")).when(tempFileCreator).createTempFile(anyString(),anyString());
   // prefer this form since it does not execute the mocked method while the when().then*() form does...

   // the rest of yout test code
}
Related