Configure TestRestTemplate using builder

Update SpringBootTestContextCustomizer to create the TestRestTemplate
using the RestTemplateBuilder whenever possible.

Fixes gh-5509
This commit is contained in:
Phillip Webb 2016-05-31 18:01:55 -07:00
parent e1d74627f5
commit 433f5e7930
4 changed files with 98 additions and 25 deletions

View File

@ -16,11 +16,19 @@
package org.springframework.boot.test.context;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.env.Environment;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.MergedContextConfiguration;
@ -38,12 +46,24 @@ class SpringBootTestContextCustomizer implements ContextCustomizer {
SpringBootTest annotation = AnnotatedElementUtils.getMergedAnnotation(
mergedContextConfiguration.getTestClass(), SpringBootTest.class);
if (annotation.webEnvironment().isEmbedded()) {
Object restTemplate = TestRestTemplateFactory
.createRestTemplate(context.getEnvironment());
context.getBeanFactory().registerSingleton("testRestTemplate", restTemplate);
registerTestRestTemplate(context);
}
}
private void registerTestRestTemplate(ConfigurableApplicationContext context) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
if (beanFactory instanceof BeanDefinitionRegistry) {
registerTestRestTemplate(context, (BeanDefinitionRegistry) context);
}
}
private void registerTestRestTemplate(ConfigurableApplicationContext context,
BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("testRestTemplate",
new RootBeanDefinition(TestRestTemplateFactory.class));
}
@Override
public int hashCode() {
return getClass().hashCode();
@ -57,13 +77,47 @@ class SpringBootTestContextCustomizer implements ContextCustomizer {
return true;
}
// Inner class to avoid references to web classes that may not be on the classpath
private static class TestRestTemplateFactory {
/**
* {@link FactoryBean} used to create a configure a {@link TestRestTemplate}.
*/
public static class TestRestTemplateFactory
implements FactoryBean<TestRestTemplate>, ApplicationContextAware {
private static TestRestTemplate createRestTemplate(Environment environment) {
TestRestTemplate template = new TestRestTemplate();
template.setUriTemplateHandler(new LocalHostUriTemplateHandler(environment));
return template;
private TestRestTemplate object;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
RestTemplateBuilder builder = getRestTemplateBuilder(applicationContext);
TestRestTemplate template = new TestRestTemplate(builder.build());
template.setUriTemplateHandler(
new LocalHostUriTemplateHandler(applicationContext.getEnvironment()));
this.object = template;
}
private RestTemplateBuilder getRestTemplateBuilder(
ApplicationContext applicationContext) {
try {
return applicationContext.getBean(RestTemplateBuilder.class);
}
catch (NoSuchBeanDefinitionException ex) {
return new RestTemplateBuilder();
}
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public Class<?> getObjectType() {
return TestRestTemplate.class;
}
@Override
public TestRestTemplate getObject() throws Exception {
return this.object;
}
}

View File

@ -91,30 +91,22 @@ public class TestRestTemplate {
*/
public TestRestTemplate(String username, String password,
HttpClientOption... httpClientOptions) {
this.restTemplate = createRestTemplate(username, password, httpClientOptions);
this(new RestTemplate(), username, password, httpClientOptions);
}
/**
* Factory method used to create the underlying {@link RestTemplate}.
* @param username the username to use (or {@code null})
* @param password the password (or {@code null})
* @param httpClientOptions client options to use if the Apache HTTP Client is used
* @return the delegate {@link RestTemplate}
*/
protected RestTemplate createRestTemplate(String username, String password,
public TestRestTemplate(RestTemplate restTemplate) {
this(restTemplate, null, null);
}
public TestRestTemplate(RestTemplate restTemplate, String username, String password,
HttpClientOption... httpClientOptions) {
RestTemplate restTemplate = new RestTemplate();
Assert.notNull(restTemplate, "RestTemplate must not be null");
if (ClassUtils.isPresent("org.apache.http.client.config.RequestConfig", null)) {
restTemplate.setRequestFactory(
new CustomHttpComponentsClientHttpRequestFactory(httpClientOptions));
}
addAuthentication(restTemplate, username, password);
restTemplate.setErrorHandler(new NoOpResponseErrorHandler());
return restTemplate;
}
public TestRestTemplate(RestTemplate restTemplate) {
Assert.notNull(restTemplate, "RestTemplate must not be null");
this.restTemplate = restTemplate;
}

View File

@ -60,6 +60,10 @@ public abstract class AbstractSpringBootTestEmbeddedWebEnvironmentTests {
@Autowired
private TestRestTemplate restTemplate;
public TestRestTemplate getRestTemplate() {
return this.restTemplate;
}
@Test
public void runAndTestHttpEndpoint() {
assertThat(this.port).isNotEqualTo(8080).isNotEqualTo(0);

View File

@ -16,15 +16,21 @@
package org.springframework.boot.test.context;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link SpringBootTest} configured with {@link WebEnvironment#RANDOM_PORT}.
*
@ -37,11 +43,28 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
public class SpringBootTestWebEnvironmentRandomPortTests
extends AbstractSpringBootTestEmbeddedWebEnvironmentTests {
@Test
public void testRestTemplateShouldUseBuilder() throws Exception {
assertThat(getRestTemplate().getRestTemplate().getMessageConverters())
.hasAtLeastOneElementOfType(MyConverter.class);
}
@Configuration
@EnableWebMvc
@RestController
protected static class Config extends AbstractConfig {
@Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder()
.additionalMessageConverters(new MyConverter());
}
}
private static class MyConverter extends StringHttpMessageConverter {
}
}