diff --git a/spring-test-mvc/src/main/java/org/springframework/test/web/client/MockMvcClientHttpRequestFactory.java b/spring-test-mvc/src/main/java/org/springframework/test/web/client/MockMvcClientHttpRequestFactory.java new file mode 100644 index 00000000000..914f949d0c5 --- /dev/null +++ b/spring-test-mvc/src/main/java/org/springframework/test/web/client/MockMvcClientHttpRequestFactory.java @@ -0,0 +1,93 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.test.web.client; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request; + +import java.io.IOException; +import java.net.URI; +import java.util.List; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.ClientHttpRequest; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.mock.http.client.MockClientHttpRequest; +import org.springframework.mock.http.client.MockClientHttpResponse; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; + +/** + * A {@link ClientHttpRequestFactory} for requests executed via {@link MockMvc}. + * + * @author Rossen Stoyanchev + * @since 3.2 + */ +public class MockMvcClientHttpRequestFactory implements ClientHttpRequestFactory { + + private final MockMvc mockMvc; + + + public MockMvcClientHttpRequestFactory(MockMvc mockMvc) { + this.mockMvc = mockMvc; + } + + public ClientHttpRequest createRequest(final URI uri, final HttpMethod httpMethod) throws IOException { + return new MockClientHttpRequest(httpMethod, uri) { + + @Override + public ClientHttpResponse executeInternal() throws IOException { + try { + MockHttpServletRequestBuilder requestBuilder = request(httpMethod, uri.toString()); + requestBuilder.content(getBodyAsBytes()); + requestBuilder.headers(getHeaders()); + + MvcResult mvcResult = MockMvcClientHttpRequestFactory.this.mockMvc.perform(requestBuilder).andReturn(); + + MockHttpServletResponse servletResponse = mvcResult.getResponse(); + HttpStatus status = HttpStatus.valueOf(servletResponse.getStatus()); + byte[] body = servletResponse.getContentAsByteArray(); + HttpHeaders headers = getResponseHeaders(servletResponse); + + MockClientHttpResponse clientResponse = new MockClientHttpResponse(body, status); + clientResponse.getHeaders().putAll(headers); + + return clientResponse; + } + catch (Exception ex) { + byte[] body = ex.toString().getBytes("UTF-8"); + return new MockClientHttpResponse(body, HttpStatus.INTERNAL_SERVER_ERROR); + } + } + }; + } + + private HttpHeaders getResponseHeaders(MockHttpServletResponse response) { + HttpHeaders headers = new HttpHeaders(); + for (String name : response.getHeaderNames()) { + List values = response.getHeaders(name); + for (String value : values) { + headers.add(name, value); + } + } + return headers; + } + +} diff --git a/spring-test-mvc/src/main/java/org/springframework/test/web/client/RequestMatcherClientHttpRequest.java b/spring-test-mvc/src/main/java/org/springframework/test/web/client/RequestMatcherClientHttpRequest.java index 9a4b4181b0d..b53caada0aa 100644 --- a/spring-test-mvc/src/main/java/org/springframework/test/web/client/RequestMatcherClientHttpRequest.java +++ b/spring-test-mvc/src/main/java/org/springframework/test/web/client/RequestMatcherClientHttpRequest.java @@ -56,7 +56,7 @@ class RequestMatcherClientHttpRequest extends MockClientHttpRequest implements R this.responseCreator = responseCreator; } - public ClientHttpResponse execute() throws IOException { + public ClientHttpResponse executeInternal() throws IOException { if (this.requestMatchers.isEmpty()) { throw new AssertionError("No request expectations to execute"); diff --git a/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java b/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java index acdc8ae15f7..26ada8e8cb0 100644 --- a/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java +++ b/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java @@ -80,6 +80,17 @@ public abstract class MockMvcRequestBuilders { return new MockHttpServletRequestBuilder(HttpMethod.DELETE, urlTemplate, urlVariables); } + /** + * Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP method. + * + * @param httpMethod the HTTP method + * @param urlTemplate a URL template; the resulting URL will be encoded + * @param urlVariables zero or more URL variables + */ + public static MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVars) { + return new MockHttpServletRequestBuilder(httpMethod, urlTemplate, urlVars); + } + /** * Create a {@link MockHttpServletRequestBuilder} for a multipart request. * diff --git a/spring-test-mvc/src/test/java/org/springframework/test/web/client/samples/MockMvcClientHttpRequestFactoryTests.java b/spring-test-mvc/src/test/java/org/springframework/test/web/client/samples/MockMvcClientHttpRequestFactoryTests.java new file mode 100644 index 00000000000..1789c436369 --- /dev/null +++ b/spring-test-mvc/src/test/java/org/springframework/test/web/client/samples/MockMvcClientHttpRequestFactoryTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.web.client.samples; + +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Controller; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.client.MockMvcClientHttpRequestFactory; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +/** + * Tests dependent on access to resources under the web application root directory. + * + * @author Rossen Stoyanchev + */ +@RunWith(SpringJUnit4ClassRunner.class) +@WebAppConfiguration +@ContextConfiguration +public class MockMvcClientHttpRequestFactoryTests { + + @Autowired + private WebApplicationContext wac; + + private RestTemplate restTemplate; + + + @Before + public void setup() { + MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).alwaysExpect(status().isOk()).build(); + this.restTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(mockMvc)); + } + + @Test + public void test() throws Exception { + String result = this.restTemplate.getForObject("/foo", String.class); + assertEquals("bar", result); + } + + + @EnableWebMvc + @Configuration + @ComponentScan(basePackageClasses=MockMvcClientHttpRequestFactoryTests.class) + static class MyWebConfig extends WebMvcConfigurerAdapter { + } + + @Controller + static class MyController { + + @RequestMapping(value="/foo", method=RequestMethod.GET) + @ResponseBody + public String handle() { + return "bar"; + } + } + +} diff --git a/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpRequest.java b/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpRequest.java index 91345526dbd..5541bddcc41 100644 --- a/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpRequest.java @@ -75,18 +75,18 @@ public class MockClientHttpRequest extends MockHttpOutputMessage implements Clie } /** - * Whether the execute method was invoked. + * Sets the {@link #isExecuted() executed} flag to true and returns the + * configured {@link #setResponse(ClientHttpResponse) response}. */ - public boolean isExecuted() { - return this.executed; + public final ClientHttpResponse execute() throws IOException { + this.executed = true; + return executeInternal(); } /** - * Sets the {@link #isExecuted() executed} flag to true and returns the - * configured {@link #setResponse(ClientHttpResponse) response}. + * Override this method to execute the request and provdie a response. */ - public ClientHttpResponse execute() throws IOException { - this.executed = true; + protected ClientHttpResponse executeInternal() throws IOException { return this.clientHttpResponse; }