简体   繁体   中英

Test multipart formdata post request

I am trying to write unit tests for a controller in spring mvc that accepts mulitpart form-data with a file along with other form data. I am able to send my request to the controller while testing but not able to access file or the data that was sent. File items received at controller seems to be empty marked 'fileItemsEmpty' in the code below. I am able to hit the api and send actual data from UI. Any help is highly appreciated.

ControllerCode:

@RequestMapping(value = "/upload-file", method = RequestMethod.POST, produces = CommonConstants.PRODUCES_JSON)
    @ResponseBody
    public String uploadFile(HttpServletRequest request, @NonNull Principal principal) throws Exception {
      try {
      String attribute1 = "";
      String attribute2 = "";
        List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
   fileItemsEmpty -> for (FileItem item : items) {
                    if(item.isFormField()) {
                      switch (item.getFieldName()) {
                            case "Attribute1":
                                attribute1 = item.getString("UTF-8");
                                break;
                            case "Attribute2":
                                attribute2 = item.getString("UTF-8");
                                break;
                            default:
                                log.info("Unknown Attribute received {}",
                                        item.getFieldName());
                        }
                    } else {
                        BufferedReader br = new BufferedReader(new InputStreamReader(item.getInputStream(), StandardCharsets.UTF_8.name()));
    
                        String line = br.readLine();
                        while (line != null) {
                          //some computation from the file
                        }
                        br.close();
                    }
                }
                } catch (FileUploadException e) {
                e.printStacktrace();
                }
                //Perform computation based on attribute1 and attribute2 and return string data.
            }

Unit test:

    @Test
    public void testfileUpload() throws Exception {

        MockMultipartFile file = new MockMultipartFile("file", "file.txt", "", "file contents".getBytes());
        MockMultipartFile attribute1 = new MockMultipartFile("Attribute1", "", "", "attribute1 value".getBytes());
        MockMultipartFile attribute2 = new MockMultipartFile("Attribute2", "", "", "attribute2 value".getBytes());

        HashMap<String, String> contentTypeParams = new HashMap<String, String>();
        contentTypeParams.put("boundary", "----WebKitFormBoundary");
        MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);


        MvcResult mvcResult =  mockMvc.perform(MockMvcRequestBuilders.fileUpload("/upload-file")
                .file(file)
                .file(attribute1)
                .file(attribute2)
                .contentType(mediaType)
                .principal(principal))
                .andExpect(status().isOk()).andReturn();
    }

Angular code:

uploadFile(event) {
    event.target.disabled = true;
    var formData = new FormData();
    formData.append('Attribute1', 'value1');
    formData.append('Attribute2', value2);
    formData.append('file', $('#fileInput')[0].files[0]);
    this.http.post<any>("/upload-file", formData);
}

You are overriding your actual file with:

 .file(file)
 .file(attribute1)
 .file(attribute2)

Both attribute1 and attribute2 are additional form data, but not files. You should not create them with MockMultipartFile but only the actual file (speak image, pdf, docx).

You can set additional form data with another method of MockMvc : .param() .

So try the following:

MvcResult mvcResult =  mockMvc
   .perform(MockMvcRequestBuilders.fileUpload("/upload-file")
   .file(file)
   .param("Attribute1", "attribute1")
   .param("Attribute2", "attribute2")
   .contentType(mediaType)
   .principal(principal))
   .andExpect(status().isOk()).andReturn();

PS: .fileUpload() is deprecated (at least in Spring Test 5.2.6) and you should favour .multipart() instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM