'MockMVC - calling a PUT endpoint that accepts a multipart file
I have a simple PUT endpoint in a Spring Boot application:
@PutMapping()
public ResponseEntity<String> upload(@RequestParam("cats") MultipartFile file) throws IOException {
I'm trying to create a test for the controller using MockMVC
:
import org.springframework.test.web.servlet.MockMvc;
@RunWith(SpringRunner.class)
@WebMvcTest(CatController.class)
public class CatControllerTest {
@Autowired
private MockMvc mockMvc;
...
For POST
endpoints I use something like that:
MockMultipartFile multipartFile = new MockMultipartFile("file", new FileInputStream("myCats.csv"));
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).alwaysDo(print()).build();
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.multipart("/uploadCats").file(multipartFile))
.andExpect(status().isOk())
.andReturn();
But when trying to translate the above call to PUT endpoint I find that I can create
MockMvcRequestBuilders.put("/catUpload")
But then I can't chain to it the multipart
Or I can do:
MockMvcRequestBuilders.multipart(...)
But then I can't chain to it the put
.
I saw some post about this problem, but they all were few years old. Is there a way to do it?
Solution 1:[1]
Using this great example I was able to solve the issues.
I'm attaching here the code with the minor updates to the post from 2016:
MockMultipartHttpServletRequestBuilder builder =
MockMvcRequestBuilders.multipart("/catUpload");
builder.with(request -> {
request.setMethod("PUT");
return request;
});
MvcResult result = mockMvc.perform(builder
.file(multipartFile))
.andExpect(status().isOk())
.andReturn();
Solution 2:[2]
As of 2022 with Spring 5.3.17 it's possible to avoid explicit builder creation leveraging static multipart request mock builder that replaces deprecated fileUpload
Unfortunately it sill has method
property hardcoded with POST
value, forcing you to change it to PUT
by its with
method accepting a RequestPostProcessor as parameter.
Being the latter a Functional Interface, lets you reduce the code by lambda expression to something like this in one of its simplest form, involving just a path parameter with value of 99 and a single file to upload and expecting a 200
response code:
mockMvc.perform(multipart("/endpoint/{pathParameter}/upload_handler", 99)
.file(mockFileToUpload)
.with(req -> { req.setMethod("PUT"); return req; }))
.andExpect(status().isOk())
At current time I didn't find any RequestPostProcessor implementation giving the ability to apply needed method modification through a builder pattern, so we're still forced using void mutator setMethod
and explicitly returning mutated argument.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | riorio |
Solution 2 | 4javier |