Reputation: 2871
I'm trying to test (through Spring test (mvc)) a controller that uses servletRequest.getParts()
All I've read so far is that MockMvcRequestBuilders.fileUpload().file()
is the solution. However I cannot make it work. I wrote the following test which fails
MockMultipartHttpServletRequestBuilder builder = MockMvcRequestBuilders.fileUpload("/foo")
.file(new MockMultipartFile("file", new byte[] { 1, 2, 3, 4 }));
MockHttpServletRequest rq = builder.buildRequest(null);
Assert.assertEquals(1, rq.getParts().size()); // result 0
I went through spring code, and the call to file(...)
adds an element in List<MockMultipartFile>
when getParts()
gets its elements from another list (Map<String, Part> parts)
There must be another way to do it...
Edit 1
The code I'm using to test the controller is :
ResultActions result = mockMvc.perform(
MockMvcRequestBuilders.fileUpload(new URI("/url")).file("param", "expected".getBytes()))
Upvotes: 7
Views: 4155
Reputation: 606
Just for reference, if you have a multipart request with multiple additional json non-file request parts you can create them like the following:
ObjectMapper objectMapper = new ObjectMapper()
// ...
// a file
MockMultipartFile file = new MockMultipartFile("file", "/some/name", "text/plain", "hello".getBytes())
// and other parts
byte[] content = objectMapper.writeValueAsBytes(somePayload)
Part somePart = new MockPart("someName", content)
somePart.getHeaders().setContentType(MediaType.APPLICATION_JSON)
and then call the service like this:
mockMvc.perform(multipart("/some/path")
.file(someFile)
.part(somePart)
.part(anotherPart))
.andExpect...
Note: sending multiple MockMultiPartFiles instead of Parts works, too. But that looks ugly.
Upvotes: 0
Reputation: 380
To elaborate on Sam Brannens answer: You can do it as follows:
Create a MockPart (instead of a MockMultipartFile) and add it using part() instead of file(); e.g:
MockPart coverPart = new MockPart("file", "1.png", Files.readAllBytes(Paths.get("images/1.png")));
coverPart.getHeaders().setContentType(MediaType.IMAGE_PNG);
And the use it in perform():
mockMvc.perform(multipart("/some/url")
.part(coverPart)
.contentType(MediaType.MULTIPART_FORM_DATA)
.andExpect(status().isOk())
Then in you controller, you will see that request.getParts() will contain a part called "file" that you can retrieve the content from using e.g. part.getInputStream().
I used the following dependency to test this: org.springframework:spring-test:5.3.14 which is included in org.springframework.boot:spring-boot-starter-test:2.6.2
Upvotes: 5
Reputation: 31247
There is currently no support for testing with javax.servlet.http.Part
in the Spring MVC Test Framework.
Consequently, I have introduced two tickets to address this shortcoming in Spring Framework 5.0:
In the interim, you should be able to mock Part
yourself and register it in the prepared MockHttpServletRequest
via a custom RequestPostProcessor
.
Regards,
Sam (author of the Spring TestContext Framework)
Upvotes: 5