yeliang99
yeliang99

Reputation: 73

How to use MockMVC test the controller which use org.apache.commons.fileupload?

My Controller use " org.apache.commons.fileupload " realized the file UPload. see it:

 @PostMapping("/upload")
    public String upload2(HttpServletRequest request) throws Exception {

        ServletFileUpload upload = new ServletFileUpload();
        FileItemIterator iter = upload.getItemIterator(request);
        boolean uploaded = false;

        while (iter.hasNext() && !uploaded) {
            FileItemStream item = iter.next();
            if (item.isFormField()) {
                item.openStream().close();
            } else {
                String fieldName = item.getFieldName();
                if (!"file".equals(fieldName)) {
                    item.openStream().close();
                } else {

                    InputStream stream = item.openStream();
                    // dosomething here.
                    uploaded = true;
                }
            }
        }
            if (uploaded) {
                return "ok";
            } else {
                throw new BaseResponseException(HttpStatus.BAD_REQUEST, "400", "no file field or data file is empty.");
            }

        }

and my MockMvc code is

    public void upload() throws Exception {
        File file = new File("/Users/jianxiaowen/Documents/a.txt");
        MockMultipartFile multipartFile = new MockMultipartFile("file", new FileInputStream(file));
        HashMap<String, String> contentTypeParams = new HashMap<String, String>();
        contentTypeParams.put("boundary", "----WebKitFormBoundaryaDEFKSFMY18ehkjt");
        MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post(baseUrl+"/upload")
                .content(multipartFile.getBytes())
                .contentType(mediaType)
                .header(Origin,OriginValue)
                .cookie(cookie))
                .andReturn();
        logResult(mvcResult);
    }

my controller is right , it has successed in my web project, but I want to test it use MvcMock, it has some mistake, see : can someOne can help me?

"status":"400","msg":"no file field or data file is empty.","data":null

I don't know why it says my file is empty. my English is poor, thank you very much if someone can help me.

Upvotes: 0

Views: 533

Answers (2)

Merbin J Anselm
Merbin J Anselm

Reputation: 1044

The MockMvc can be used for integration testing for controllers using Apache Commons Fileupload too!

  1. Import the org.apache.httpcomponents:httpmime into your pom.xml or gradle.properties

    <dependency>
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpmime</artifactId>
       <version>4.5.13</version>
    </dependency>
    
  2. Update the code to use MultipartEntityBuilder to build the multipart request on the client, and then serialize the entity into bytes, which is then set in the request content

    public void upload() throws Exception {
        File file = new File("/Users/jianxiaowen/Documents/a.txt");
    
        String boundary = "----WebKitFormBoundaryaDEFKSFMY18ehkjt";
    
        // create 'Content-Type' header for multipart along with boundary
        HashMap<String, String> contentTypeParams = new HashMap<String, String>();
        contentTypeParams.put("boundary", boundary); // set boundary in the header
        MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);
    
        // create a multipart entity builder, and add parts (file/form data)
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        HttpEntity multipartEntity = MultipartEntityBuilder.create()
            .addPart("file", new FileBody(file, ContentType.create("text/plain"), file.getName())) // add file
            // .addTextBody("param1", "value1") // optionally add form data
            .setBoundary(boundary) // set boundary to be used
            .build();
        multipartEntity.writeTo(outputStream); // or getContent() to get content stream
        byte[] content = outputStream.toByteArray(); // serialize the content to bytes
    
        MvcResult mvcResult = mockMvc.perform(
            MockMvcRequestBuilders.post(baseUrl + "/upload")
                .contentType(mediaType)
                .content(content) // finally set the content
                .header(Origin,OriginValue)
                .cookie(cookie)
            ).andReturn();
        logResult(mvcResult);
    }
    

Upvotes: 5

MohamedSanaulla
MohamedSanaulla

Reputation: 6242

Can you try the below?

mockMvc.perform(
  MockMvcRequestBuilders.multipart(baseUrl+"/upload")
    .file(multiPartFile)
).andReturn();

Update:

You need to update the controller to handle the MultipartFile:

@PostMapping("/upload")
public String upload2(@RequestParam(name="nameOfRequestParamWhichContainsFileData")
     MultipartFile uploadedFile, HttpServletRequest request) throws Exception {
  //the uploaded file gets copied to uploadedFile object. 
}

You need not use another library for managing file uploads. You can use the file upload capabilities provided by Spring MVC.

Upvotes: 0

Related Questions