diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/IntegrationTestPropertiesListener.java b/spring-boot-test/src/main/java/org/springframework/boot/test/IntegrationTestPropertiesListener.java index 9eb7f8c0ec..39b211e3b7 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/IntegrationTestPropertiesListener.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/IntegrationTestPropertiesListener.java @@ -16,16 +16,56 @@ package org.springframework.boot.test; +import org.springframework.boot.test.context.IntegrationTest; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.test.context.MergedContextConfiguration; +import org.springframework.test.context.TestContext; +import org.springframework.test.context.support.AbstractTestExecutionListener; +import org.springframework.test.util.ReflectionTestUtils; + /** * Manipulate the TestContext to merge properties from {@code @IntegrationTest}. * * @author Dave Syer * @author Phillip Webb * @since 1.2.0 - * @deprecated since 1.4.0 in favor of IntegrationTestPropertiesListener + * @deprecated since 1.4.0 as no longer used by {@code @IntegrationTest}. */ @Deprecated -public class IntegrationTestPropertiesListener - extends org.springframework.boot.test.context.IntegrationTestPropertiesListener { +public class IntegrationTestPropertiesListener extends AbstractTestExecutionListener { + + @Override + public void prepareTestInstance(TestContext testContext) throws Exception { + Class> testClass = testContext.getTestClass(); + AnnotationAttributes annotationAttributes = AnnotatedElementUtils + .getMergedAnnotationAttributes(testClass, + IntegrationTest.class.getName()); + if (annotationAttributes != null) { + addPropertySourceProperties(testContext, + annotationAttributes.getStringArray("value")); + } + } + + private void addPropertySourceProperties(TestContext testContext, + String[] properties) { + try { + MergedContextConfiguration configuration = (MergedContextConfiguration) ReflectionTestUtils + .getField(testContext, "mergedContextConfiguration"); + new MergedContextConfigurationProperties(configuration).add(properties); + } + catch (RuntimeException ex) { + throw ex; + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } } diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/MergedContextConfigurationProperties.java b/spring-boot-test/src/main/java/org/springframework/boot/test/MergedContextConfigurationProperties.java similarity index 88% rename from spring-boot-test/src/main/java/org/springframework/boot/test/context/MergedContextConfigurationProperties.java rename to spring-boot-test/src/main/java/org/springframework/boot/test/MergedContextConfigurationProperties.java index c55338c21c..a2d44a5978 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/MergedContextConfigurationProperties.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/MergedContextConfigurationProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.test.context; +package org.springframework.boot.test; import java.util.Arrays; import java.util.LinkedHashSet; @@ -28,14 +28,14 @@ import org.springframework.test.util.ReflectionTestUtils; * Provides access to {@link MergedContextConfiguration} properties. * * @author Phillip Webb - * @since 1.4.0 + * @deprecated since 1.4.0 along with {@link IntegrationTestPropertiesListener} */ -public class MergedContextConfigurationProperties { +@Deprecated +class MergedContextConfigurationProperties { private final MergedContextConfiguration configuration; - public MergedContextConfigurationProperties( - MergedContextConfiguration configuration) { + MergedContextConfigurationProperties(MergedContextConfiguration configuration) { this.configuration = configuration; } diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/SpringApplicationContextLoader.java b/spring-boot-test/src/main/java/org/springframework/boot/test/SpringApplicationContextLoader.java index c22d9af9ac..85a9ac6424 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/SpringApplicationContextLoader.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/SpringApplicationContextLoader.java @@ -17,6 +17,7 @@ package org.springframework.boot.test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.test.context.SpringApplicationTest; import org.springframework.mock.web.MockServletContext; import org.springframework.test.context.ContextLoader; @@ -35,11 +36,16 @@ import org.springframework.test.context.ContextLoader; * @author Dave Syer * @author Phillip Webb * @author Andy Wilkinson - * @see IntegrationTest - * @see WebIntegrationTest - * @see TestRestTemplate + * @see org.springframework.boot.test.context.SpringApplicationTest + * @see org.springframework.boot.test.context.IntegrationTest + * @see org.springframework.boot.test.context.web.WebIntegrationTest * @deprecated since 1.4.0 in favor of - * {@link org.springframework.boot.test.context.SpringApplicationContextLoader} + * {@link SpringApplicationTest @SpringApplicationTest}, + * {@link org.springframework.boot.test.context.IntegrationTest @IntegrationTest}, + * {@link org.springframework.boot.test.context.web.WebIntegrationTest @WebIntegrationTest} + * annotations. + * {@link org.springframework.boot.test.context.SpringApplicationContextLoader} can also + * be considered if absolutely necessary. */ @Deprecated public class SpringApplicationContextLoader diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTest.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTest.java index bed0ab54f9..9fd0d43cf3 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTest.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTest.java @@ -23,36 +23,42 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.ApplicationContext; import org.springframework.core.env.Environment; -import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; -import org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener; -import org.springframework.test.context.support.DirtiesContextTestExecutionListener; -import org.springframework.test.context.transaction.TransactionalTestExecutionListener; +import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; /** - * Test class annotation signifying that the tests are "integration tests" and therefore - * require full startup in the same way as a production application. Normally used in - * conjunction with {@code @SpringApplicationConfiguration}. + * Test class annotation signifying that the tests are "integration tests" for a + * {@link org.springframework.boot.SpringApplication Spring Boot Application}. By default + * will load nested {@code @Configuration} classes, or fallback an + * {@link SpringApplicationConfiguration @SpringApplicationConfiguration} search. Unless + * otherwise configured, a {@link SpringApplicationContextLoader} will be used to load the + * {@link ApplicationContext}. Use + * {@link SpringApplicationConfiguration @SpringApplicationConfiguration} or + * {@link ContextConfiguration @ContextConfiguration} if custom configuration is required. *
- * If your test also uses {@code @WebAppConfiguration} consider using the
- * {@link org.springframework.boot.test.context.web.WebIntegrationTest} instead.
+ * It's recommended that {@code @IntegrationTest} is used only for non-web applications
+ * (i.e. not combined with {@link WebAppConfiguration @WebAppConfiguration}). If you want
+ * to start a real embedded servlet container in the same way as a production application
+ * (listening on normal ports) use
+ * {@link org.springframework.boot.test.context.web.WebIntegrationTest @WebIntegrationTest}
+ * instead. If you are testing a web 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.
*
* @author Dave Syer
+ * @author Phillip Webb
+ * @see SpringApplicationTest
* @see org.springframework.boot.test.context.web.WebIntegrationTest
*/
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-// Leave out the ServletTestExecutionListener because it only deals with Mock* servlet
-// stuff. A real embedded application will not need the mocks.
-@TestExecutionListeners(listeners = { IntegrationTestPropertiesListener.class,
- DirtiesContextBeforeModesTestExecutionListener.class,
- DependencyInjectionTestExecutionListener.class,
- DirtiesContextTestExecutionListener.class,
- TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class })
+@BootstrapWith(IntegrationTestContextBootstrapper.class)
public @interface IntegrationTest {
/**
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTestContextBootstrapper.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTestContextBootstrapper.java
new file mode 100644
index 0000000000..23d2595806
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTestContextBootstrapper.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.test.context.MergedContextConfiguration;
+import org.springframework.test.context.TestContextBootstrapper;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.context.web.WebMergedContextConfiguration;
+
+/**
+ * {@link TestContextBootstrapper} for {@link IntegrationTest}.
+ *
+ * @author Phillip Webb
+ */
+class IntegrationTestContextBootstrapper extends SpringBootTestContextBootstrapper {
+
+ private static final String SERVLET_LISTENER = "org.springframework.test.context.web.ServletTestExecutionListener";
+
+ @Override
+ protected List
* Similar to the standard {@link ContextConfiguration @ContextConfiguration} but uses
* Spring Boot's {@link SpringApplicationContextLoader}.
+ *
+ * Tests that using this annotation only to define {@code classes} should consider using
+ * {@link SpringApplicationTest @SpringApplicationTest},
+ * {@link IntegrationTest @IntegrationTest} or
+ * {@link org.springframework.boot.test.context.web.WebIntegrationTest @WebIntegrationTest}
+ * instead.
*
* @author Dave Syer
* @author Sam Brannen
+ * @author Phillip Webb
+ * @since 1.4.0
+ * @see SpringApplicationTest
+ * @see IntegrationTest
+ * @see org.springframework.boot.test.context.web.WebIntegrationTest
* @see SpringApplicationContextLoader
* @see ContextConfiguration
*/
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationContextLoader.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationContextLoader.java
index 704503d072..7787ea92eb 100644
--- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationContextLoader.java
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationContextLoader.java
@@ -16,7 +16,6 @@
package org.springframework.boot.test.context;
-import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -29,20 +28,16 @@ import java.util.Set;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.web.ServletContextApplicationContextInitializer;
-import org.springframework.boot.test.context.web.WebIntegrationTest;
import org.springframework.boot.test.mock.web.SpringBootMockServletContext;
import org.springframework.boot.test.util.EnvironmentTestUtils;
-import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.SpringVersion;
import org.springframework.core.annotation.AnnotatedElementUtils;
-import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
-import org.springframework.mock.web.MockServletContext;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextLoader;
@@ -50,7 +45,6 @@ import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.support.AbstractContextLoader;
import org.springframework.test.context.support.AnnotationConfigContextLoaderUtils;
import org.springframework.test.context.support.TestPropertySourceUtils;
-import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.context.web.WebMergedContextConfiguration;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -59,12 +53,22 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
/**
* A {@link ContextLoader} that can be used to test Spring Boot applications (those that
- * normally startup using {@link SpringApplication}). Can be used to test non-web features
- * (like a repository layer) or start an fully-configured embedded servlet container.
- *
- * Use {@code @WebIntegrationTest} (or {@code @IntegrationTest} with
- * {@code @WebAppConfiguration}) to indicate that you want to use a real servlet container
- * or {@code @WebAppConfiguration} alone to use a {@link MockServletContext}.
+ * normally startup using {@link SpringApplication}). Although this loader can be used
+ * directly, most test will instead want to use one of the following annotations:
+ *
* If {@code @ActiveProfiles} are provided in the test class they will be used to create
* the application context.
@@ -72,16 +76,26 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
* @author Dave Syer
* @author Phillip Webb
* @author Andy Wilkinson
+ * @see SpringApplicationTest
* @see IntegrationTest
- * @see WebIntegrationTest
- * @see TestRestTemplate
+ * @see org.springframework.boot.test.context.web.WebIntegrationTest
*/
public class SpringApplicationContextLoader extends AbstractContextLoader {
+ private static final Set
+ * A mock servlet environment will used when this annotation is used to a test web
+ * application. If you want to start a real embedded servlet container in the same way as
+ * a production application (listening on normal ports) the
+ * {@link org.springframework.boot.test.context.web.WebIntegrationTest @WebIntegrationTest}
+ * annotation should be used instead. If you are testing a non-web application, and you
+ * don't need a mock servlet environment you should switch to
+ * {@link IntegrationTest @IntegrationTest}.
+ *
+ * @author Phillip Webb
+ * @since 1.4.0
+ * @see IntegrationTest
+ * @see org.springframework.boot.test.context.web.WebIntegrationTest
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@BootstrapWith(SpringApplicationTestContextBootstrapper.class)
+public @interface SpringApplicationTest {
+
+ /**
+ * Properties in form {@literal key=value} that should be added to the Spring
+ * {@link Environment} before the test runs.
+ */
+ String[] value() default {};
+
+}
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationTestContextBootstrapper.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationTestContextBootstrapper.java
new file mode 100644
index 0000000000..64eba434dd
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationTestContextBootstrapper.java
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.test.context.MergedContextConfiguration;
+import org.springframework.test.context.TestContext;
+import org.springframework.test.context.TestContextBootstrapper;
+import org.springframework.test.context.web.ServletTestExecutionListener;
+import org.springframework.test.context.web.WebMergedContextConfiguration;
+import org.springframework.util.ClassUtils;
+
+/**
+ * {@link TestContextBootstrapper} for {@link SpringApplicationTest}.
+ *
+ * @author Phillip Webb
+ */
+class SpringApplicationTestContextBootstrapper extends SpringBootTestContextBootstrapper {
+
+ private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
+ "org.springframework.web.context.ConfigurableWebApplicationContext" };
+
+ @Override
+ public TestContext buildTestContext() {
+ TestContext context = super.buildTestContext();
+ if (isWebApplicationTest()) {
+ context.setAttribute(ServletTestExecutionListener.ACTIVATE_LISTENER, true);
+ }
+ return context;
+ }
+
+ @Override
+ protected MergedContextConfiguration processMergedContextConfiguration(
+ MergedContextConfiguration mergedConfig) {
+ mergedConfig = super.processMergedContextConfiguration(mergedConfig);
+ if (!(mergedConfig instanceof WebMergedContextConfiguration)
+ && isWebApplicationTest()) {
+ mergedConfig = new WebMergedContextConfiguration(mergedConfig, "");
+ }
+ return mergedConfig;
+ }
+
+ private boolean isWebApplicationTest() {
+ for (String className : WEB_ENVIRONMENT_CLASSES) {
+ if (!ClassUtils.isPresent(className, null)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected void processPropertySourceProperties(
+ MergedContextConfiguration mergedConfig,
+ List
- * This annotation can be used as an alternative to {@code @IntegrationTest} and
- * {@code @WebAppConfiguration}.
+ * If you are not testing a web application consider using the
+ * {@link IntegrationTest @IntegrationTest} annotation instead. If you are testing a web
+ * 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.
*
* @author Phillip Webb
- * @since 1.2.1
- * @see org.springframework.boot.test.context.IntegrationTest
+ * @since 1.4.0
+ * @see SpringApplicationTest
+ * @see IntegrationTest
*/
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-@BootstrapWith(WebAppIntegrationTestContextBootstrapper.class)
+@BootstrapWith(WebIntegrationTestContextBootstrapper.class)
public @interface WebIntegrationTest {
/**
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebAppIntegrationTestContextBootstrapper.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTestContextBootstrapper.java
similarity index 56%
rename from spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebAppIntegrationTestContextBootstrapper.java
rename to spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTestContextBootstrapper.java
index 3356146499..1abdd39218 100644
--- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebAppIntegrationTestContextBootstrapper.java
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/web/WebIntegrationTestContextBootstrapper.java
@@ -16,11 +16,14 @@
package org.springframework.boot.test.context.web;
-import org.springframework.boot.test.context.MergedContextConfigurationProperties;
+import java.util.Arrays;
+import java.util.List;
+
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.TestContextBootstrapper;
+import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.context.web.WebMergedContextConfiguration;
/**
@@ -28,26 +31,36 @@ import org.springframework.test.context.web.WebMergedContextConfiguration;
*
* @author Phillip Webb
*/
-class WebAppIntegrationTestContextBootstrapper extends SpringBootTestContextBootstrapper {
+class WebIntegrationTestContextBootstrapper extends SpringBootTestContextBootstrapper {
@Override
protected MergedContextConfiguration processMergedContextConfiguration(
MergedContextConfiguration mergedConfig) {
+ assertValidAnnotations(mergedConfig.getTestClass());
mergedConfig = super.processMergedContextConfiguration(mergedConfig);
- WebIntegrationTest annotation = AnnotatedElementUtils.findMergedAnnotation(
+ return new WebMergedContextConfiguration(mergedConfig, null);
+ }
+
+ private void assertValidAnnotations(Class> testClass) {
+ if (AnnotatedElementUtils.findMergedAnnotation(testClass,
+ WebAppConfiguration.class) != null
+ && AnnotatedElementUtils.findMergedAnnotation(testClass,
+ WebIntegrationTest.class) != null) {
+ throw new IllegalStateException("@WebIntegrationTest and "
+ + "@WebAppConfiguration cannot be used together");
+ }
+ }
+
+ @Override
+ protected void processPropertySourceProperties(
+ MergedContextConfiguration mergedConfig,
+ List
+ *
+ * The loader supports both standard {@link MergedContextConfiguration} as well as
+ * {@link WebMergedContextConfiguration}. If {@link WebMergedContextConfiguration} is used
+ * the context will either use a mock servlet environment, or start the full embedded
+ * servlet container (depending on the result of {@link #isIntegrationTest
+ * isIntegrationTest(...)}).
*