Enterprise Java

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 called MockMultipartFile 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.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
St1mpy
St1mpy
2 years ago

What should the fileService do in the 2nd test? You do not use it at all

Back to top button