Using Spring MVC Test to unit test multipart POST request
Since MockMvcRequestBuilders#fileUpload
is deprecated, you'll want to use MockMvcRequestBuilders#multipart(String, Object...)
which returns a MockMultipartHttpServletRequestBuilder
. Then chain a bunch of file(MockMultipartFile)
calls.
Here's a working example. Given a @Controller
@Controllerpublic class NewController { @RequestMapping(value = "/upload", method = RequestMethod.POST) @ResponseBody public String saveAuto( @RequestPart(value = "json") JsonPojo pojo, @RequestParam(value = "some-random") String random, @RequestParam(value = "data", required = false) List<MultipartFile> files) { System.out.println(random); System.out.println(pojo.getJson()); for (MultipartFile file : files) { System.out.println(file.getOriginalFilename()); } return "success"; } static class JsonPojo { private String json; public String getJson() { return json; } public void setJson(String json) { this.json = json; } }}
and a unit test
@WebAppConfiguration@ContextConfiguration(classes = WebConfig.class)@RunWith(SpringJUnit4ClassRunner.class)public class Example { @Autowired private WebApplicationContext webApplicationContext; @Test public void test() throws Exception { MockMultipartFile firstFile = new MockMultipartFile("data", "filename.txt", "text/plain", "some xml".getBytes()); MockMultipartFile secondFile = new MockMultipartFile("data", "other-file-name.data", "text/plain", "some other type".getBytes()); MockMultipartFile jsonFile = new MockMultipartFile("json", "", "application/json", "{\"json\": \"someValue\"}".getBytes()); MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); mockMvc.perform(MockMvcRequestBuilders.multipart("/upload") .file(firstFile) .file(secondFile) .file(jsonFile) .param("some-random", "4")) .andExpect(status().is(200)) .andExpect(content().string("success")); }}
And the @Configuration
class
@Configuration@ComponentScan({ "test.controllers" })@EnableWebMvcpublic class WebConfig extends WebMvcConfigurationSupport { @Bean public MultipartResolver multipartResolver() { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); return multipartResolver; }}
The test should pass and give you output of
4 // from paramsomeValue // from json filefilename.txt // from first fileother-file-name.data // from second file
The thing to note is that you are sending the JSON just like any other multipart file, except with a different content type.
The method MockMvcRequestBuilders.fileUpload
is deprecated use MockMvcRequestBuilders.multipart
instead.
This is an example:
import static org.hamcrest.CoreMatchers.containsString;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.Mockito;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;import org.springframework.boot.test.mock.mockito.MockBean;import org.springframework.mock.web.MockMultipartFile;import org.springframework.test.context.junit4.SpringRunner;import org.springframework.test.web.servlet.MockMvc;import org.springframework.test.web.servlet.ResultActions;import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;import org.springframework.test.web.servlet.result.MockMvcResultHandlers;import org.springframework.test.web.servlet.setup.MockMvcBuilders;import org.springframework.web.context.WebApplicationContext;import org.springframework.web.multipart.MultipartFile;/** * Unit test New Controller. * */@RunWith(SpringRunner.class)@WebMvcTest(NewController.class)public class NewControllerTest { private MockMvc mockMvc; @Autowired WebApplicationContext wContext; @MockBean private NewController newController; @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(wContext) .alwaysDo(MockMvcResultHandlers.print()) .build(); } @Test public void test() throws Exception { // Mock Request MockMultipartFile jsonFile = new MockMultipartFile("test.json", "", "application/json", "{\"key1\": \"value1\"}".getBytes()); // Mock Response NewControllerResponseDto response = new NewControllerDto(); Mockito.when(newController.postV1(Mockito.any(Integer.class), Mockito.any(MultipartFile.class))).thenReturn(response); mockMvc.perform(MockMvcRequestBuilders.multipart("/fileUpload") .file("file", jsonFile.getBytes()) .characterEncoding("UTF-8")) .andExpect(status().isOk()); }}
Have a look at this example taken from the spring MVC showcase, this is the link to the source code:
@RunWith(SpringJUnit4ClassRunner.class)public class FileUploadControllerTests extends AbstractContextControllerTests { @Test public void readString() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); webAppContextSetup(this.wac).build() .perform(fileUpload("/fileupload").file(file)) .andExpect(model().attribute("message", "File 'orig' uploaded successfully")); }}