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?