diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java index c7ec885a67a142729cb61f62f8c9503329a97c7d..87594e4820f3592e8e85956661041b2dcc9daf86 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java @@ -16,6 +16,9 @@ package org.springframework.test.web.servlet.request; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.security.Principal; @@ -33,8 +36,10 @@ import javax.servlet.http.Cookie; import org.springframework.beans.Mergeable; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; @@ -603,24 +608,10 @@ public class MockHttpServletRequestBuilder } } - try { - if (this.url.getRawQuery() != null) { - request.setQueryString(this.url.getRawQuery()); - } - - MultiValueMap queryParams = - UriComponentsBuilder.fromUri(this.url).build().getQueryParams(); - - for (Entry> entry : queryParams.entrySet()) { - for (String value : entry.getValue()) { - value = (value != null) ? UriUtils.decode(value, "UTF-8") : null; - request.addParameter(UriUtils.decode(entry.getKey(), "UTF-8"), value); - } - } - } - catch (UnsupportedEncodingException ex) { - // shouldn't happen + if (this.url.getRawQuery() != null) { + request.setQueryString(this.url.getRawQuery()); } + addRequestParams(request, UriComponentsBuilder.fromUri(this.url).build().getQueryParams()); for (String name : this.parameters.keySet()) { for (String value : this.parameters.get(name)) { @@ -632,6 +623,13 @@ public class MockHttpServletRequestBuilder request.setContent(this.content); request.setCharacterEncoding(this.characterEncoding); + if (this.content != null && this.contentType != null) { + MediaType mediaType = MediaType.parseMediaType(this.contentType); + if (MediaType.APPLICATION_FORM_URLENCODED.includes(mediaType)) { + addRequestParams(request, parseFormData(mediaType)); + } + } + if (!ObjectUtils.isEmpty(this.cookies)) { request.setCookies(this.cookies.toArray(new Cookie[this.cookies.size()])); } @@ -695,6 +693,43 @@ public class MockHttpServletRequestBuilder request.setPathInfo(this.pathInfo); } + private void addRequestParams(MockHttpServletRequest request, MultiValueMap map) { + try { + for (Entry> entry : map.entrySet()) { + for (String value : entry.getValue()) { + value = (value != null) ? UriUtils.decode(value, "UTF-8") : null; + request.addParameter(UriUtils.decode(entry.getKey(), "UTF-8"), value); + } + } + } + catch (UnsupportedEncodingException ex) { + // shouldn't happen + } + } + + private MultiValueMap parseFormData(final MediaType mediaType) { + MultiValueMap map;HttpInputMessage message = new HttpInputMessage() { + @Override + public InputStream getBody() throws IOException { + return new ByteArrayInputStream(content); + } + + @Override + public HttpHeaders getHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(mediaType); + return headers; + } + }; + try { + map = new FormHttpMessageConverter().read(null, message); + } + catch (IOException ex) { + throw new IllegalStateException("Failed to parse form data in request body: ", ex); + } + return map; + } + private FlashMapManager getFlashMapManager(MockHttpServletRequest request) { FlashMapManager flashMapManager = null; try { diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java index 5057e4c4044ce59018a325176bac91799930b14b..53c76989da29a51630b9088a34f53db66469b9b9 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java @@ -18,6 +18,7 @@ package org.springframework.test.web.servlet.request; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.nio.charset.Charset; import java.security.Principal; import java.util.Arrays; import java.util.Collections; @@ -272,6 +273,20 @@ public class MockHttpServletRequestBuilderTests { assertArrayEquals(new String[] {"bar", "baz"}, request.getParameterMap().get("foo")); } + @Test + public void requestParameterFromRequestBodyFormData() throws Exception { + String contentType = "application/x-www-form-urlencoded;charset=UTF-8"; + String body = "name+1=value+1&name+2=value+A&name+2=value+B&name+3"; + + MockHttpServletRequest request = new MockHttpServletRequestBuilder(HttpMethod.POST, "/foo") + .contentType(contentType).content(body.getBytes(Charset.forName("UTF-8"))) + .buildRequest(this.servletContext); + + assertArrayEquals(new String[] {"value 1"}, request.getParameterMap().get("name 1")); + assertArrayEquals(new String[] {"value A", "value B"}, request.getParameterMap().get("name 2")); + assertArrayEquals(new String[] {null}, request.getParameterMap().get("name 3")); + } + @Test public void acceptHeader() { this.builder.accept(MediaType.TEXT_HTML, MediaType.APPLICATION_XML); diff --git a/src/asciidoc/whats-new.adoc b/src/asciidoc/whats-new.adoc index 4907766934d67251cae1da9d136045084b2e9956..079d690794182f4e20932fd057b379013862c581 100644 --- a/src/asciidoc/whats-new.adoc +++ b/src/asciidoc/whats-new.adoc @@ -672,5 +672,6 @@ Spring 4.3 also improves the caching abstraction as follows: === Testing Improvements * The JUnit support in the _Spring TestContext Framework_ now requires JUnit 4.12 or higher. +* Server-side Spring MVC Test supports expectations on response headers with multiple values. +* Server-side Spring MVC Test parses form data request content and populates request parameters. * Client-side Spring MVC Test supports expectations for form data in the request body. -* Server-side Spring MVC Test supports expectations on response headers with multiple values. \ No newline at end of file