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 c1f044d6f883..afa712b3c910 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 @@ -28,6 +28,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.stream.Collectors; import javax.servlet.ServletContext; import javax.servlet.ServletRequest; import javax.servlet.http.Cookie; @@ -99,6 +100,9 @@ public class MockHttpServletRequestBuilder @Nullable private Boolean secure; + @Nullable + private String queryString = ""; + @Nullable private Principal principal; @@ -353,6 +357,40 @@ public MockHttpServletRequestBuilder params(MultiValueMap params return this; } + /** + * Add a query parameter to the {@link MockHttpServletRequest}. + *

If called more than once, new values get added to existing ones. + * @param name the parameter name + * @param values one or more values + */ + public MockHttpServletRequestBuilder queryParam(String name, String... values) { + param(name, values); + String builder = Arrays.stream(values).map(value -> UriUtils.encode(name, StandardCharsets.UTF_8) + + ((value != null) ? ("=" + UriUtils.encode(value, StandardCharsets.UTF_8)) : "") + "&" + ).collect(Collectors.joining()); + queryString += builder; + return this; + } + + /** + * Add a map of query parameters to the {@link MockHttpServletRequest}, + * for example when testing a form submission. + *

If called more than once, new values get added to existing ones. + * @param params the parameters to add + * @since 4.2.4 + */ + public MockHttpServletRequestBuilder queryParams(MultiValueMap params) { + params(params); + StringBuilder builder = new StringBuilder(); + params.forEach((key, values) -> values.forEach(value -> { + builder.append(UriUtils.encode(key, StandardCharsets.UTF_8)) + .append(((value != null) ? ("=" + UriUtils.encode(value, StandardCharsets.UTF_8)) : "")) + .append("&"); + })); + queryString += builder.toString(); + return this; + } + /** * Add the given cookies to the request. Cookies are always added. * @param cookies the cookies to add @@ -635,13 +673,24 @@ public final MockHttpServletRequest buildRequest(ServletContext servletContext) request.setQueryString(this.url.getRawQuery()); } addRequestParams(request, UriComponentsBuilder.fromUri(this.url).build().getQueryParams()); - this.parameters.forEach((name, values) -> { for (String value : values) { request.addParameter(name, value); } }); + StringBuilder queryBuilder = new StringBuilder(); + if (request.getQueryString() != null) { + queryBuilder.append(request.getQueryString()); + } + if (this.queryString != null && !"".equals(this.queryString)) { + if (queryBuilder.length() > 0) { + queryBuilder.append("&"); + } + queryBuilder.append(this.queryString, 0, this.queryString.length() - 1); + request.setQueryString(queryBuilder.toString()); + } + if (this.content != null && this.content.length > 0) { String requestContentType = request.getContentType(); if (requestContentType != null) { 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 384ddca574ce..6a36a752ee20 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 @@ -21,6 +21,7 @@ import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.security.Principal; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -233,6 +234,47 @@ public void requestParameterFromQueryList() { assertThat(request.getParameter("foo[1]")).isEqualTo("baz"); } + @Test + public void requestParameterToQuery() { + this.builder = new MockHttpServletRequestBuilder(HttpMethod.GET, "/"); + this.builder.queryParam("foo", "bar"); + this.builder.queryParam("foo", "baz"); + + MockHttpServletRequest request = this.builder.buildRequest(this.servletContext); + + assertThat(request.getParameterMap().get("foo")).isEqualTo(new String[] {"bar", "baz"}); + assertThat(request.getQueryString()).isEqualTo("foo=bar&foo=baz"); + } + + @Test + public void requestParameterMapToQuery() { + this.builder = new MockHttpServletRequestBuilder(HttpMethod.GET, "/"); + MultiValueMap queryParams = new LinkedMultiValueMap<>(); + List values = new ArrayList<>(); + values.add("bar"); + values.add("baz"); + queryParams.put("foo", values); + this.builder.queryParams(queryParams); + + MockHttpServletRequest request = this.builder.buildRequest(this.servletContext); + + assertThat(request.getParameterMap().get("foo")).isEqualTo(new String[] {"bar", "baz"}); + assertThat(request.getQueryString()).isEqualTo("foo=bar&foo=baz"); + } + + @Test + public void requestParameterToQueryList() { + this.builder = new MockHttpServletRequestBuilder(HttpMethod.GET, "/"); + this.builder.queryParam("foo[0]", "bar"); + this.builder.queryParam("foo[1]", "baz"); + + MockHttpServletRequest request = this.builder.buildRequest(this.servletContext); + + assertThat(request.getQueryString()).isEqualTo("foo%5B0%5D=bar&foo%5B1%5D=baz"); + assertThat(request.getParameter("foo[0]")).isEqualTo("bar"); + assertThat(request.getParameter("foo[1]")).isEqualTo("baz"); + } + @Test public void requestParameterFromQueryWithEncoding() { this.builder = new MockHttpServletRequestBuilder(HttpMethod.GET, "/?foo={value}", "bar=baz");