Skip to content

Commit 3a50daf

Browse files
committed
Add MockMvcClientHttpRequestFactory
Issue: SPR-9917
1 parent f30d33d commit 3a50daf

File tree

5 files changed

+200
-8
lines changed

5 files changed

+200
-8
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2002-2012 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.test.web.client;
17+
18+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
19+
20+
import java.io.IOException;
21+
import java.net.URI;
22+
import java.util.List;
23+
24+
import org.springframework.http.HttpHeaders;
25+
import org.springframework.http.HttpMethod;
26+
import org.springframework.http.HttpStatus;
27+
import org.springframework.http.client.ClientHttpRequest;
28+
import org.springframework.http.client.ClientHttpRequestFactory;
29+
import org.springframework.http.client.ClientHttpResponse;
30+
import org.springframework.mock.http.client.MockClientHttpRequest;
31+
import org.springframework.mock.http.client.MockClientHttpResponse;
32+
import org.springframework.mock.web.MockHttpServletResponse;
33+
import org.springframework.test.web.servlet.MockMvc;
34+
import org.springframework.test.web.servlet.MvcResult;
35+
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
36+
37+
/**
38+
* A {@link ClientHttpRequestFactory} for requests executed via {@link MockMvc}.
39+
*
40+
* @author Rossen Stoyanchev
41+
* @since 3.2
42+
*/
43+
public class MockMvcClientHttpRequestFactory implements ClientHttpRequestFactory {
44+
45+
private final MockMvc mockMvc;
46+
47+
48+
public MockMvcClientHttpRequestFactory(MockMvc mockMvc) {
49+
this.mockMvc = mockMvc;
50+
}
51+
52+
public ClientHttpRequest createRequest(final URI uri, final HttpMethod httpMethod) throws IOException {
53+
return new MockClientHttpRequest(httpMethod, uri) {
54+
55+
@Override
56+
public ClientHttpResponse executeInternal() throws IOException {
57+
try {
58+
MockHttpServletRequestBuilder requestBuilder = request(httpMethod, uri.toString());
59+
requestBuilder.content(getBodyAsBytes());
60+
requestBuilder.headers(getHeaders());
61+
62+
MvcResult mvcResult = MockMvcClientHttpRequestFactory.this.mockMvc.perform(requestBuilder).andReturn();
63+
64+
MockHttpServletResponse servletResponse = mvcResult.getResponse();
65+
HttpStatus status = HttpStatus.valueOf(servletResponse.getStatus());
66+
byte[] body = servletResponse.getContentAsByteArray();
67+
HttpHeaders headers = getResponseHeaders(servletResponse);
68+
69+
MockClientHttpResponse clientResponse = new MockClientHttpResponse(body, status);
70+
clientResponse.getHeaders().putAll(headers);
71+
72+
return clientResponse;
73+
}
74+
catch (Exception ex) {
75+
byte[] body = ex.toString().getBytes("UTF-8");
76+
return new MockClientHttpResponse(body, HttpStatus.INTERNAL_SERVER_ERROR);
77+
}
78+
}
79+
};
80+
}
81+
82+
private HttpHeaders getResponseHeaders(MockHttpServletResponse response) {
83+
HttpHeaders headers = new HttpHeaders();
84+
for (String name : response.getHeaderNames()) {
85+
List<String> values = response.getHeaders(name);
86+
for (String value : values) {
87+
headers.add(name, value);
88+
}
89+
}
90+
return headers;
91+
}
92+
93+
}

spring-test-mvc/src/main/java/org/springframework/test/web/client/RequestMatcherClientHttpRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public void andRespond(ResponseCreator responseCreator) {
5656
this.responseCreator = responseCreator;
5757
}
5858

59-
public ClientHttpResponse execute() throws IOException {
59+
public ClientHttpResponse executeInternal() throws IOException {
6060

6161
if (this.requestMatchers.isEmpty()) {
6262
throw new AssertionError("No request expectations to execute");

spring-test-mvc/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ public static MockHttpServletRequestBuilder delete(String urlTemplate, Object...
8080
return new MockHttpServletRequestBuilder(HttpMethod.DELETE, urlTemplate, urlVariables);
8181
}
8282

83+
/**
84+
* Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP method.
85+
*
86+
* @param httpMethod the HTTP method
87+
* @param urlTemplate a URL template; the resulting URL will be encoded
88+
* @param urlVariables zero or more URL variables
89+
*/
90+
public static MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVars) {
91+
return new MockHttpServletRequestBuilder(httpMethod, urlTemplate, urlVars);
92+
}
93+
8394
/**
8495
* Create a {@link MockHttpServletRequestBuilder} for a multipart request.
8596
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.web.client.samples;
18+
19+
import static org.junit.Assert.*;
20+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
21+
22+
import org.junit.Before;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.context.annotation.ComponentScan;
27+
import org.springframework.context.annotation.Configuration;
28+
import org.springframework.stereotype.Controller;
29+
import org.springframework.test.context.ContextConfiguration;
30+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
31+
import org.springframework.test.context.web.WebAppConfiguration;
32+
import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
33+
import org.springframework.test.web.servlet.MockMvc;
34+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
35+
import org.springframework.web.bind.annotation.RequestMapping;
36+
import org.springframework.web.bind.annotation.RequestMethod;
37+
import org.springframework.web.bind.annotation.ResponseBody;
38+
import org.springframework.web.client.RestTemplate;
39+
import org.springframework.web.context.WebApplicationContext;
40+
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
41+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
42+
43+
/**
44+
* Tests dependent on access to resources under the web application root directory.
45+
*
46+
* @author Rossen Stoyanchev
47+
*/
48+
@RunWith(SpringJUnit4ClassRunner.class)
49+
@WebAppConfiguration
50+
@ContextConfiguration
51+
public class MockMvcClientHttpRequestFactoryTests {
52+
53+
@Autowired
54+
private WebApplicationContext wac;
55+
56+
private RestTemplate restTemplate;
57+
58+
59+
@Before
60+
public void setup() {
61+
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).alwaysExpect(status().isOk()).build();
62+
this.restTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(mockMvc));
63+
}
64+
65+
@Test
66+
public void test() throws Exception {
67+
String result = this.restTemplate.getForObject("/foo", String.class);
68+
assertEquals("bar", result);
69+
}
70+
71+
72+
@EnableWebMvc
73+
@Configuration
74+
@ComponentScan(basePackageClasses=MockMvcClientHttpRequestFactoryTests.class)
75+
static class MyWebConfig extends WebMvcConfigurerAdapter {
76+
}
77+
78+
@Controller
79+
static class MyController {
80+
81+
@RequestMapping(value="/foo", method=RequestMethod.GET)
82+
@ResponseBody
83+
public String handle() {
84+
return "bar";
85+
}
86+
}
87+
88+
}

spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpRequest.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,18 @@ public void setResponse(ClientHttpResponse clientHttpResponse) {
7575
}
7676

7777
/**
78-
* Whether the execute method was invoked.
78+
* Sets the {@link #isExecuted() executed} flag to true and returns the
79+
* configured {@link #setResponse(ClientHttpResponse) response}.
7980
*/
80-
public boolean isExecuted() {
81-
return this.executed;
81+
public final ClientHttpResponse execute() throws IOException {
82+
this.executed = true;
83+
return executeInternal();
8284
}
8385

8486
/**
85-
* Sets the {@link #isExecuted() executed} flag to true and returns the
86-
* configured {@link #setResponse(ClientHttpResponse) response}.
87+
* Override this method to execute the request and provdie a response.
8788
*/
88-
public ClientHttpResponse execute() throws IOException {
89-
this.executed = true;
89+
protected ClientHttpResponse executeInternal() throws IOException {
9090
return this.clientHttpResponse;
9191
}
9292

0 commit comments

Comments
 (0)