Add multipart support for MockMvcTester
File uploads with MockMvc require a separate MockHttpServletRequestBuilder implementation. This commit applies the same change to support AssertJ on this builder, but for the multipart version. Any request builder can now use `multipart()` to "down cast" to a dedicated multipart request builder that contains the settings configured thus far. Closes gh-33027
This commit is contained in:
@@ -20,6 +20,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -31,6 +32,7 @@ import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.Part;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@@ -44,6 +46,8 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.mock.web.MockPart;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
|
||||
import org.springframework.test.web.Person;
|
||||
@@ -54,13 +58,19 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.support.MissingServletRequestPartException;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
@@ -113,6 +123,41 @@ public class MockMvcTesterIntegrationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class MultipartTests {
|
||||
|
||||
private final MockMultipartFile JSON_PART_FILE = new MockMultipartFile("json", "json", "application/json", """
|
||||
{
|
||||
"name": "test"
|
||||
}""".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
@Test
|
||||
void multipartWithPut() {
|
||||
MockMultipartFile part = new MockMultipartFile("file", "content.txt", null, "value".getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(mvc.put().uri("/multipart-put").multipart().file(part).file(JSON_PART_FILE))
|
||||
.hasStatusOk()
|
||||
.hasViewName("index")
|
||||
.model().contains(entry("name", "file"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipartWithMissingPart() {
|
||||
assertThat(mvc.put().uri("/multipart-put").multipart().file(JSON_PART_FILE))
|
||||
.hasStatus(HttpStatus.BAD_REQUEST)
|
||||
.failure().isInstanceOfSatisfying(MissingServletRequestPartException.class,
|
||||
ex -> assertThat(ex.getRequestPartName()).isEqualTo("file"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipartWithNamedPart() {
|
||||
MockPart part = new MockPart("part", "content.txt", "value".getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(mvc.post().uri("/part").multipart().part(part).file(JSON_PART_FILE))
|
||||
.hasStatusOk()
|
||||
.hasViewName("index")
|
||||
.model().contains(entry("part", "content.txt"), entry("name", "test"));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class CookieTests {
|
||||
|
||||
@@ -516,7 +561,7 @@ public class MockMvcTesterIntegrationTests {
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@Import({ TestController.class, PersonController.class, AsyncController.class,
|
||||
SessionController.class, ErrorController.class })
|
||||
MultipartController.class, SessionController.class, ErrorController.class })
|
||||
static class WebConfiguration {
|
||||
}
|
||||
|
||||
@@ -564,6 +609,22 @@ public class MockMvcTesterIntegrationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
static class MultipartController {
|
||||
|
||||
@PostMapping("/part")
|
||||
ModelAndView part(@RequestPart Part part, @RequestPart Map<String, String> json) {
|
||||
Map<String, Object> model = new HashMap<>(json);
|
||||
model.put(part.getName(), part.getSubmittedFileName());
|
||||
return new ModelAndView("index", model);
|
||||
}
|
||||
|
||||
@PutMapping("/multipart-put")
|
||||
public ModelAndView multiPartViaHttpPut(@RequestParam MultipartFile file) {
|
||||
return new ModelAndView("index", Map.of("name", file.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
@SessionAttributes("locale")
|
||||
static class SessionController {
|
||||
|
||||
Reference in New Issue
Block a user