Reputation: 1159
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
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
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