Testing the File Upload API in Spring Boot
In one of my previous post, I had created an API to upload file. In this post I will write a JUnit test to test the API. We will test the complete flow right from uploading till it is copied to the file system and then we will also see how to mock the FileService class so that the uploaded file is not copied to the file system.
File Upload REST API
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | @Slf4j @RestController @RequestMapping ( "/api/files" ) public class FileUploadAPIController { @Autowired FileService fileService; @PostMapping ( "/upload" ) public ResponseEntity<?> handleFileUpload( @RequestParam ( "uploaded-file" ) List<MultipartFile> uploadedFiles ) throws IOException { log.debug( "Uploaded files size : {}" , uploadedFiles.size()); fileService.copyFile(uploadedFiles); return ResponseEntity.ok().build(); } } |
- Line 1-4: Declaring a RESTful API with base URL: /api/files
- Line 6: Injecting the
FileService
managed bean used for copying the uploaded file to file system - Lne 8: Mapping the upload API to be available via HTTP POST to the URL: /api/files/upload
- Line 10: Accepting more than 1 file uploaded using the request param name
uploaded-file
- Line 12-14: Implementation of the API
Testing the API without mocking FileService
The below code is for testing the file upload API. In this we are going to test the complete flow where a file is sent to the API and then copid to the file system:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | @SpringBootTest @AutoConfigureMockMvc public class FileUploadAPIControllerE2ETest { @Autowired MockMvc mockMvc; @Value ( "${app.document-root}" )String documentRoot; List<Path> filesToBeDeleted = new ArrayList<>(); @Test public void test_handleFileUpload() throws Exception { String fileName = "sampleFile.txt" ; MockMultipartFile sampleFile = new MockMultipartFile( "uploaded-file" , fileName, "text/plain" , "This is the file content" .getBytes() ); MockMultipartHttpServletRequestBuilder multipartRequest = MockMvcRequestBuilders.multipart( "/api/files/upload" ); mockMvc.perform(multipartRequest.file(sampleFile)) .andExpect(status().isOk()); Path docRootPath = Path.of(documentRoot, fileName); filesToBeDeleted.add(docRootPath); assertThat(Files.exists(docRootPath)).isTrue(); } @AfterEach public void cleanup() { filesToBeDeleted.forEach(path -> { try { Files.deleteIfExists(path); } catch (IOException e) { e.printStackTrace(); } }); } } |
- Line 1-2:
@SpringBootTest
annoation creates a mock web server and@AutoConfigureMockMvc
configures a@MockMvc
object which can be used for invoking the APIs defined in the code - Line 7: Injecting the root directoy path where the files are copied. We will use this to validate that the file was actually copied when we invoked the API for testing.
- Line 9, 33-42: Recording the location of the uploaded files in the file system, so that we can cleanup at the end of each test. This way our tests will be repeatable.
- Line 13-19: Creating the file to be uploaded. Spring provides an implementation of
MultipartFile
calledMockMultipartFile
which can be used for providing files to the API. - Line 21-25: Invoking the API by providing the file created before and asserting that the response is HTTP status 200.
- Line 27-29: Doing the assertion that the file was copied to the required destination.
Testing the API with mock FileService
In this testing we will mock the FileService
bean, using @MockBean
, which is the bean responsible for copying the uploaded file to the required location in the file system. In this test we will just test the API code without concenring the downstream services it depends on.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | @SpringBootTest @AutoConfigureMockMvc public class FileUploadAPIControllerTest { @MockBean private FileService fileService; @Autowired MockMvc mockMvc; @Value ( "${app.document-root}" )String documentRoot; @Test public void test_handleFileUpload() throws Exception{ String fileName = "sample-file-mock.txt" ; MockMultipartFile sampleFile = new MockMultipartFile( "uploaded-file" , fileName, "text/plain" , "This is the file content" .getBytes()); MockMultipartHttpServletRequestBuilder multipartRequest = MockMvcRequestBuilders.multipart( "/api/files/upload" ); mockMvc.perform(multipartRequest.file(sampleFile)) .andExpect(status().isOk()); } @Test public void test_handleFileUpload_NoFileProvided() throws Exception{ MockMultipartHttpServletRequestBuilder multipartRequest = MockMvcRequestBuilders.multipart( "/api/files/upload" ); mockMvc.perform(multipartRequest) .andExpect(status().isBadRequest()); } } |
- Line 4: Mocking the spring managed bean
FileService
using Mockito via the annotation@MockBean
. This annotation is useful to mock spring managed beans
Rest of the code is similar to the one in end to end test previously shown. In this test we dont validate the existence of the file on the file system because the implementation of copying to file system has been mocked and there is no real implementation in the mocked managed bean.
The complete code – API, View and Tests can be found in the Github repo here.
Published on Java Code Geeks with permission by Mohamed Sanaulla, partner at our JCG program. See the original article here: Testing the File Upload API in Spring Boot
Opinions expressed by Java Code Geeks contributors are their own. |
What should the fileService do in the 2nd test? You do not use it at all