stephenbakalian
stephenbakalian

Reputation: 1159

How to upload file in spring integration test and set it to a parameter?

I'm attempting to do some Integration Testing on a page that has a file upload as part of a form. I haven't seen anything similar to my situation

Everything works fine on the actual page, so I'm pretty sure it has something to do with the way I'm doing my test. If i'm understanding everything correctly then the issue is because the file upload is happening through the header in the test and not through the form. If someone could guide me in the right direction or point out what I'm doing wrong, it would be greatly appreciated.

Controller

@Controller
@RequestMapping("/report")
public class ReportController
{
    @RequestMapping(value = { "/", "" }, method = RequestMethod.POST, params = { "download" })
    public String generateReport(HttpServletRequest request, HttpServletResponse response, @Valid @ModelAttribute("report") ReportForm form, BindingResult bindingResult, Model model)throws Exception
    {
        //logic
    }
//other functions
}

Form (ReportForm)

public class ReportForm
{
    //Other variables 

    @NotNull
    private MultipartFile importFile;

    //getters and setters
}

jspx

<form:form modelAttribute="report" method="POST" acceptCharset="UTF-8" enctype="multipart/form-data">
    <!-- custom file import-->
    <form:file mandatory="true" label="Upload File" path="importFile" divClass="box-100"/>

    <!-- other form stuff -->
    <div id="button-box">
        <input type="submit" value="download report" name="download" class="button-accent" />
    </div>
</form:form>

Test

@Test
public void when_Http_Post_Correct_File() throws Exception
{
    File report = new File("report.dbf");
    //Logic creating and populating dbf

    InputStream inputstream = new FileInputStream(report);
    MockMultipartFile acceptFile = new MockMultipartFile("importFile", inputstream);

    mockMvc.perform(MockMvcRequestBuilders.fileUpload("/reports")
                    .file(acceptFile)
                    .param("download", "download")
                    .param("some other param", "value"))
      .andDo(print())
      .andExpect(status().isOk())
      .andExpect(model().attributeHasNoErrors("importFile"));

}

Trace

2014-08-26 09:08:06,111 ERROR [com.test.BaseConfiguredTestApplication] - JUnit: Failed With Following Exception {}
java.lang.AssertionError: No BindingResult for attribute: importFile
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:39)
at org.springframework.test.util.AssertionErrors.assertTrue(AssertionErrors.java:72)
at org.springframework.test.web.servlet.result.ModelResultMatchers.getBindingResult(ModelResultMatchers.java:241)
at org.springframework.test.web.servlet.result.ModelResultMatchers.access$100(ModelResultMatchers.java:38)
at org.springframework.test.web.servlet.result.ModelResultMatchers$7.match(ModelResultMatchers.java:145)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:149)
at com.test.ReportTest.when_Http_Post_Correct_File(ReportTest.java:90)

The view is returning an error 500 with this as it's value

org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found

Upvotes: 2

Views: 4981

Answers (2)

kazbeel
kazbeel

Reputation: 1436

I know you have already achieved a solution although I would recommend you to make use of fileUpload().

Take a look at this example:

@Test
    public void readString() throws Exception {

        MockMultipartFile file = new MockMultipartFile("file", "original_filename.ext", null, "data".getBytes());

        webAppContextSetup(this.wac).build()
                .perform(fileUpload("/fileupload").file(file))
                .andExpect(model().attribute("message", "Attachment uploaded successfully"));
}

Upvotes: 0

stephenbakalian
stephenbakalian

Reputation: 1159

Managed to figure out that one way to do it is to sent the content type and enter in the content yourself.

First you need to set up the content-type

    HashMap<String, String> contentTypeParams = new HashMap<String, String>();
    //boundary value can be anything
    contentTypeParams.put("boundary", "A1152");
    MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);

Next is to translate the file into a way the content can read it

    byte[] fileData = new byte[(int) file.length()];
    InputStream inputstream = new FileInputStream(file);
    inputstream.read(fileData);
    inputstream.close();
    //Set the bytes to a string for 'octet-stream' to read
    String content = new String(fileData);

Create form content to be uploaded, here you'll need the empty form params as well as the file params. You'll also need the boundary value at the begining of each param. Build A multipart/form-data POST request.

    String contentValue= "--A1152\r\nContent-Disposition: form-data; name=\"formValue1\"\r\n\r\nValue for form value 1\r\n" 
            + "--A1152\r\nContent-Disposition: form-data; name=\"importFile\"; filename=\""
            + file.getName()
            + "\"\r\nContent-Type: "
            //content type, in this case application/octet-stream
            + "application/octet-stream"
            + "\r\n\r\n"
            + content 
            + "\r\n--A1152\r\nContent-Disposition: form-data; name=\"dataLyr\"\r\n\r\n\r\n" 
            + "--A1152\r\nContent-Disposition: form-data; name=\"nullFormValue\"\r\n\r\n\r\n"
            + "--A1152\r\nContent-Disposition: form-data; name=\"download\"\r\n\r\ndownload\r\n"
            + "--A1152--\r\n";

then you do your mockMvc test passing in the content type and content and then expect what ever you want form it

mockMvc.perform(post("/reports")
    .contentType(mediaType)
    .content(contentValue))
  .andExpect(something);

Upvotes: 1

Related Questions