diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTest.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTest.java index 2303e9d0cef..b04d9ba71ce 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTest.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTest.java @@ -23,10 +23,13 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.beans.factory.annotation.Autowire; import org.springframework.boot.test.context.IntegrationTest; import org.springframework.boot.test.context.SpringApplicationConfiguration; import org.springframework.boot.test.context.SpringApplicationContextLoader; import org.springframework.boot.test.context.SpringApplicationTest; +import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler; +import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.context.ApplicationContext; import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; @@ -49,6 +52,10 @@ import org.springframework.test.web.servlet.MockMvc; * application and want to mock the servlet environment (for example so that you can use * {@link MockMvc}) you should switch to the * {@link SpringApplicationTest @SpringApplicationTest} annotation. + *

+ * Tests that need to make REST calls to the started server can additionally + * {@link Autowire @Autowire} a {@link TestRestTemplate} which will be pre-configured with + * a {@link LocalHostUriTemplateHandler}. * * @author Phillip Webb * @since 1.4.0 diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTestContextCustomizer.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTestContextCustomizer.java new file mode 100644 index 00000000000..035cc0774ed --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTestContextCustomizer.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2016 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.boot.test.context.web; + +import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextCustomizer; +import org.springframework.test.context.MergedContextConfiguration; + +/** + * {@link ContextCustomizer} for {@link WebIntegrationTest} that provides a + * {@link TestRestTemplate} bean that can automatically resolve + * {@literal local.server.port}. + * + * @author Phillip Webb + */ +class WebIntegrationTestContextCustomizer implements ContextCustomizer { + + @Override + public void customizeContext(ConfigurableApplicationContext context, + MergedContextConfiguration mergedContextConfiguration) { + TestRestTemplate restTemplate = getRestTemplate(context.getEnvironment()); + context.getBeanFactory().registerSingleton("testRestTemplate", restTemplate); + } + + private TestRestTemplate getRestTemplate(Environment environment) { + TestRestTemplate template = new TestRestTemplate(); + template.setUriTemplateHandler(new LocalHostUriTemplateHandler(environment)); + return template; + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + return true; + } + +} diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTestContextCustomizerFactory.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTestContextCustomizerFactory.java new file mode 100644 index 00000000000..d731d8210c2 --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTestContextCustomizerFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2016 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.boot.test.context.web; + +import java.util.List; + +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.ContextConfigurationAttributes; +import org.springframework.test.context.ContextCustomizer; +import org.springframework.test.context.ContextCustomizerFactory; + +/** + * {@link ContextCustomizerFactory} for {@link WebIntegrationTest}. + * + * @author Phillip Webb + * @see WebIntegrationTestContextCustomizer + */ +class WebIntegrationTestContextCustomizerFactory implements ContextCustomizerFactory { + + @Override + public ContextCustomizer createContextCustomizer(Class testClass, + List configAttributes) { + if (AnnotatedElementUtils.findMergedAnnotation(testClass, + WebIntegrationTest.class) != null) { + return new WebIntegrationTestContextCustomizer(); + } + return null; + } + +} diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/LocalHostUriTemplateHandler.java b/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/LocalHostUriTemplateHandler.java new file mode 100644 index 00000000000..1e4b4a3f868 --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/LocalHostUriTemplateHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2016 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.boot.test.web.client; + +import org.springframework.core.env.Environment; +import org.springframework.util.Assert; +import org.springframework.web.util.DefaultUriTemplateHandler; +import org.springframework.web.util.UriTemplateHandler; + +/** + * {@link UriTemplateHandler} will automatically prefix relative URLs with + * localhost:${local.server.port}. + * + * @author Phillip Webb + * @since 1.4.0 + */ +public class LocalHostUriTemplateHandler extends DefaultUriTemplateHandler { + + private final Environment environment; + + public LocalHostUriTemplateHandler(Environment environment) { + Assert.notNull(environment, "Environment must not be null"); + this.environment = environment; + } + + @Override + public String getBaseUrl() { + String port = this.environment.getProperty("local.server.port", "8080"); + return "http://localhost:" + port; + } + +} diff --git a/spring-boot-test/src/main/resources/META-INF/spring.factories b/spring-boot-test/src/main/resources/META-INF/spring.factories index 90927f93b90..50479f73419 100644 --- a/spring-boot-test/src/main/resources/META-INF/spring.factories +++ b/spring-boot-test/src/main/resources/META-INF/spring.factories @@ -1,6 +1,7 @@ # Spring Test ContextCustomizerFactories org.springframework.test.context.ContextCustomizerFactory=\ org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizerFactory,\ +org.springframework.boot.test.context.web.WebIntegrationTestContextCustomizerFactory,\ org.springframework.boot.test.mock.mockito.MockitoContextCustomizerFactory # Test Execution Listeners diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/LocalHostUriTemplateHandlerTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/LocalHostUriTemplateHandlerTests.java new file mode 100644 index 00000000000..c056cd4f414 --- /dev/null +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/LocalHostUriTemplateHandlerTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2016 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.boot.test.web.client; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.mock.env.MockEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link LocalHostUriTemplateHandler}. + * + * @author Phillip Webb + */ +public class LocalHostUriTemplateHandlerTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void createWhenEnvironmentIsNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Environment must not be null"); + new LocalHostUriTemplateHandler(null); + } + + @Test + public void getBaseUrlShouldUseLocalServerPort() throws Exception { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("local.server.port", "1234"); + LocalHostUriTemplateHandler handler = new LocalHostUriTemplateHandler( + environment); + assertThat(handler.getBaseUrl()).isEqualTo("http://localhost:1234"); + } + + @Test + public void getBaseUrlWhenLocalServerPortMissingShouldUsePort8080() throws Exception { + MockEnvironment environment = new MockEnvironment(); + LocalHostUriTemplateHandler handler = new LocalHostUriTemplateHandler( + environment); + assertThat(handler.getBaseUrl()).isEqualTo("http://localhost:8080"); + } + +}