Hi,
I have implemented a file upload controller and I need to write an integration test for that controller by using spring-test-mvc. However, I cannot get the test pass. I will explain the implementation of my controller next.
First, I declared a multipart resolver bean in my application context configuration class:
Code:
@Bean
public CommonsMultipartResolver multipartResolver(){
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(5242880);
return resolver;
}
Second, I implemented the actual controller class:
Code:
@Controller
public class ImageUploadController {
@RequestMapping(value = "/person/{personId}/image", method = RequestMethod.POST)
@ResponseBody
public String uploadImage(@RequestParam("image") MultipartFile image,
@PathVariable("personId") Long personId) {
//Processes image
//Returns the url of the image
}
}
I configured my integration test by following these steps:
- Configure the used test runner class
- Configure the application context configuration class and use the WebContextLoader class to load web application context
- Inject FilterChainProxy (I need to ensure that the function is secured as well) and WebApplicationContext into the test class
- Create MockMvc object in a method called setUp()
The source code of my configuration looks as follows:
Code:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {FooWebApplicationContext.class}, loader = WebContextLoader.class)
public class ITImageUploadControllerTest {
@Resource
private FilterChainProxy springSecurityFilterChain;
@Resource
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.webApplicationContextSetup(webApplicationContext)
.addFilter(springSecurityFilterChain)
.build();
}
//Tests are here
}
My first attempt was this:
Code:
@Test
public void uploadImageAsAnonymous() throws Exception {
MockMultipartFile file = new MockMultipartFile("image", "FooBar".getBytes());
mockMvc.perform(fileUpload("/person/{personId}/image", Long.valueOf(1))
.file(file)
)
.andExpect(status().isUnauthorized());
}
When I ran the test, I got the following exception:
Code:
org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
When I was debugging this test, I noticed that the multipart boundary was not set to the headers of the request. I tried to fix this by using following test:
Code:
@Test
public void uploadImageAsAnonymous() throws Exception {
MockMultipartFile file = new MockMultipartFile("image", "--265001916915724 FooBar --265001916915724--".getBytes());
Map<String, String> contentTypeParameters = new HashMap<String, String>();
contentTypeParameters.put("boundary", "265001916915724");
MediaType contentType = new MediaType("multipart", "form-data", contentTypeParameters);
mockMvc.perform(fileUpload("/person/{personId}/image", Long.valueOf(1))
.file(file)
.contentType(contentType)
)
.andExpect(status().isUnauthorized());
}
Unfortunately this throws a NPE:
Code:
Caused by: java.lang.NullPointerException
at java.io.FilterInputStream.read(FilterInputStream.java:116)
at org.apache.commons.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:125)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:976)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:886)
at java.io.InputStream.read(InputStream.java:85)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:96)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:66)
at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:592)
at org.apache.commons.fileupload.MultipartStream.discardBodyData(MultipartStream.java:618)
at org.apache.commons.fileupload.MultipartStream.skipPreamble(MultipartStream.java:637)
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:984)
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:965)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:351)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:156)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:139)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1020)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:883)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
... 75 more
My third attempt was to add the contents of the file to the request body:
Code:
@Test
public void uploadImageAsAnonymous() throws Exception {
MockMultipartFile file = new MockMultipartFile("image", "--265001916915724 FooBar --265001916915724--".getBytes());
Map<String, String> contentTypeParameters = new HashMap<String, String>();
contentTypeParameters.put("boundary", "265001916915724");
MediaType contentType = new MediaType("multipart", "form-data", contentTypeParameters);
mockMvc.perform(fileUpload("/person/{personId}/image", Long.valueOf(1))
.body(file.getBytes())
.contentType(contentType)
)
.andExpect(status().isUnauthorized());
}
Unfortunately this did not work either. Now I a got an error about missing parameter:
Code:
org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'image' is not present
I am running out of ideas. Any ideas what could be wrong?