Announcement Announcement Module
Collapse
No announcement yet.
Writing an integration test for file upload controller with spring-test-mvc Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Writing an integration test for file upload controller with spring-test-mvc

    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?

  • #2
    When you use perform(fileUpload(..)), it sets up a MockMultipartHttpServletRequest. Since the request is already a MultipartHttpServletRequest, there is no need to parse it, which is what CommonsMultipartResolver tries to do. If you remove the CommonsMultipartResolver from the configuration (or exclude it by using a profile), it should work. The framework tests include a FileUploadControllerTests.

    Comment


    • #3
      Rossen,

      thank you for your answer. That solved my problem!

      Comment

      Working...
      X