javajunitspring-data-jpaspring-test

How to test internal workings of a function that returns an object that was mocked?


I am still somewhat new to JUnit and writing tests for my Java Springboot application.

I want to test a function within a service that looks like this:

public UploadedScanQueryFile store(MultipartFile file) {
        
    UploadedScanQueryFile newFileRecord = new UploadedScanQueryFile();
        
    newFileRecord.setUploadDateTime(LocalDateTime.now(ZoneOffset.UTC));
    try {
        newFileRecord.setFile(file.getBytes());
    } catch (IOException ex) {
        log.debug("Exception when trying to get bytes form file : {}", ex.toString());
    }
    newFileRecord.setFileName(file.getOriginalFilename());

    return fileRepository.save(newFileRecord);
}

fileRepository is a MongoDB service.

My JUnit test looks like this:

@MockBean UploadedScanQueryFileRepository fileRepository;

@Test
void doValidStoreTest() throws IOException {
    String filename = "ScanQueryUploadTestFile.csv";
    File testCSVfile = new ClassPathResource(filename).getFile();
    InputStream testCSVInputStream = new FileInputStream(testCSVfile);
    MockMultipartFile testCSVMultipartFile = new MockMultipartFile(filename, testCSVInputStream);

    UploadedScanQueryFile result = new UploadedScanQueryFile();
    result.setFileName(filename);
    result.setId(99);
when(fileRepository.save(org.mockito.ArgumentMatchers.any(UploadedScanQueryFile.class))).thenReturn(result);

    storageService.store(testCSVMultipartFile);

    assertEquals(99, result.getId());

}

My problem is that I have no real way to test that the method is doing what it should because the object it returns is simply the Mocked object that I pass in.

The internal workings set various parameter values, but I can't check them because they're internal to the method and not exposed to the test (as it's the mocked value that is returned).

Does anyone have any suggestions on how best to test in this scenario?

I have written the above test class, which basically runs the method to ensure that it doesn't throw an exception, but that doesn't test the internal workings are doing the correct thing,


Solution

  • Mockito provides an ArgumentCaptor mechanism that should be helpful here.

    Class level:

        // declare mock beans...
    
        @Captor 
        ArgumentCaptor<UploadedScanQueryFile> fileRecordCaptor;
    

    In your test, you can verify that the repository save was invoked and capture the a reference to the newFileRecord parameter:

        Mockito.verify(fileRepository).save(fileRecordCaptor.capture());
        var savedFile = fileRecordCaptor.getValue();
        /// your assertions... 
        assertEquals(expectedFilename, savedFile.getFilename())