{
+
+ @Override
+ public void initialize(final ConfigurableApplicationContext applicationContext) {
+ new ConfigFileApplicationListener() {
+ public void apply() {
+ addPropertySources(applicationContext.getEnvironment(),
+ applicationContext);
+ addPostProcessors(applicationContext);
+ }
+ }.apply();
+ }
+
+}
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
new file mode 100644
index 0000000000..bed0ab54f9
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+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;
+
+/**
+ * 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}.
+ *
+ * If your test also uses {@code @WebAppConfiguration} consider using the
+ * {@link org.springframework.boot.test.context.web.WebIntegrationTest} instead.
+ *
+ * @author Dave Syer
+ * @see org.springframework.boot.test.context.web.WebIntegrationTest
+ */
+@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 })
+public @interface IntegrationTest {
+
+ /**
+ * Properties in form {@literal key=value} that should be added to the Spring
+ * {@link Environment} before the test runs.
+ * @return the environment properties
+ */
+ String[] value() default {};
+
+}
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTestPropertiesListener.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTestPropertiesListener.java
new file mode 100644
index 0000000000..a405ed57f6
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/IntegrationTestPropertiesListener.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2013-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 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.4.0
+ */
+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/MergedContextConfigurationProperties.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/MergedContextConfigurationProperties.java
similarity index 84%
rename from spring-boot-test/src/main/java/org/springframework/boot/test/MergedContextConfigurationProperties.java
rename to spring-boot-test/src/main/java/org/springframework/boot/test/context/MergedContextConfigurationProperties.java
index 8898e7b173..c55338c21c 100644
--- a/spring-boot-test/src/main/java/org/springframework/boot/test/MergedContextConfigurationProperties.java
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/MergedContextConfigurationProperties.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package org.springframework.boot.test;
+package org.springframework.boot.test.context;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
+import org.springframework.boot.test.context.web.WebIntegrationTest;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.util.ReflectionTestUtils;
@@ -27,13 +28,14 @@ import org.springframework.test.util.ReflectionTestUtils;
* Provides access to {@link MergedContextConfiguration} properties.
*
* @author Phillip Webb
- * @since 1.2.1
+ * @since 1.4.0
*/
-class MergedContextConfigurationProperties {
+public class MergedContextConfigurationProperties {
private final MergedContextConfiguration configuration;
- MergedContextConfigurationProperties(MergedContextConfiguration configuration) {
+ public MergedContextConfigurationProperties(
+ MergedContextConfiguration configuration) {
this.configuration = configuration;
}
@@ -55,7 +57,7 @@ class MergedContextConfigurationProperties {
* @param propertySourceProperties the property source properties
*/
private void addIntegrationTestProperty(Set propertySourceProperties) {
- propertySourceProperties.add(IntegrationTest.class.getName() + "=true");
+ propertySourceProperties.add(WebIntegrationTest.class.getName() + "=true");
}
}
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationConfiguration.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationConfiguration.java
new file mode 100644
index 0000000000..95ea77bba1
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationConfiguration.java
@@ -0,0 +1,106 @@
+/*
+ * 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.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.annotation.AliasFor;
+import org.springframework.test.context.ContextConfiguration;
+
+/**
+ * Class-level annotation that is used to determine how to load and configure an
+ * {@code ApplicationContext} for integration tests.
+ *
+ * Similar to the standard {@link ContextConfiguration @ContextConfiguration} but uses
+ * Spring Boot's {@link SpringApplicationContextLoader}.
+ *
+ * @author Dave Syer
+ * @author Sam Brannen
+ * @see SpringApplicationContextLoader
+ * @see ContextConfiguration
+ */
+@ContextConfiguration(loader = SpringApplicationContextLoader.class)
+@Documented
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface SpringApplicationConfiguration {
+
+ /**
+ * The context configuration classes.
+ * @see ContextConfiguration#classes()
+ * @return the context configuration classes
+ */
+ @AliasFor("classes")
+ Class>[] value() default {};
+
+ /**
+ * The context configuration locations.
+ * @see ContextConfiguration#locations()
+ * @return the context configuration locations
+ */
+ @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
+ String[] locations() default {};
+
+ /**
+ * The context configuration classes.
+ * @see ContextConfiguration#classes()
+ * @return the context configuration classes
+ */
+ @AliasFor("value")
+ Class>[] classes() default {};
+
+ /**
+ * The context configuration initializers.
+ * @see ContextConfiguration#initializers()
+ * @return the context configuration initializers
+ */
+ @AliasFor(annotation = ContextConfiguration.class, attribute = "initializers")
+ Class extends ApplicationContextInitializer extends ConfigurableApplicationContext>>[] initializers() default {};
+
+ /**
+ * Should context locations be inherited.
+ * @see ContextConfiguration#inheritLocations()
+ * @return {@code true} if context locations should be inherited
+ */
+ @AliasFor(annotation = ContextConfiguration.class, attribute = "inheritLocations")
+ boolean inheritLocations() default true;
+
+ /**
+ * Should initializers be inherited.
+ * @see ContextConfiguration#inheritInitializers()
+ * @return {@code true} if context initializers should be inherited
+ */
+ @AliasFor(annotation = ContextConfiguration.class, attribute = "inheritInitializers")
+ boolean inheritInitializers() default true;
+
+ /**
+ * The name of the context hierarchy level.
+ * @see ContextConfiguration#name()
+ * @return the name of the context hierarchy level
+ */
+ @AliasFor(annotation = ContextConfiguration.class, attribute = "name")
+ String name() default "";
+
+}
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
new file mode 100644
index 0000000000..6a5afb0d69
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringApplicationContextLoader.java
@@ -0,0 +1,288 @@
+/*
+ * 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.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+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.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.ContextLoader;
+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;
+import org.springframework.util.StringUtils;
+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}.
+ *
+ * If {@code @ActiveProfiles} are provided in the test class they will be used to create
+ * the application context.
+ *
+ * @author Dave Syer
+ * @author Phillip Webb
+ * @author Andy Wilkinson
+ * @see IntegrationTest
+ * @see WebIntegrationTest
+ * @see TestRestTemplate
+ */
+public class SpringApplicationContextLoader extends AbstractContextLoader {
+
+ @Override
+ public ApplicationContext loadContext(final MergedContextConfiguration config)
+ throws Exception {
+ assertValidAnnotations(config.getTestClass());
+ SpringApplication application = getSpringApplication();
+ application.setMainApplicationClass(config.getTestClass());
+ application.setSources(getSources(config));
+ ConfigurableEnvironment environment = new StandardEnvironment();
+ if (!ObjectUtils.isEmpty(config.getActiveProfiles())) {
+ setActiveProfiles(environment, config.getActiveProfiles());
+ }
+ Map properties = getEnvironmentProperties(config);
+ addProperties(environment, properties);
+ application.setEnvironment(environment);
+ List> initializers = getInitializers(config,
+ application);
+ if (config instanceof WebMergedContextConfiguration) {
+ new WebConfigurer().configure(config, application, initializers);
+ }
+ else {
+ application.setWebEnvironment(false);
+ }
+ application.setInitializers(initializers);
+ ConfigurableApplicationContext applicationContext = application.run();
+ return applicationContext;
+ }
+
+ private void assertValidAnnotations(Class> testClass) {
+ if (AnnotatedElementUtils.isAnnotated(testClass, WebAppConfiguration.class)
+ && AnnotatedElementUtils.isAnnotated(testClass,
+ WebIntegrationTest.class)) {
+ throw new IllegalStateException("@WebIntegrationTest and "
+ + "@WebAppConfiguration cannot be used together");
+ }
+ }
+
+ /**
+ * Builds new {@link org.springframework.boot.SpringApplication} instance. You can
+ * override this method to add custom behavior
+ * @return {@link org.springframework.boot.SpringApplication} instance
+ */
+ protected SpringApplication getSpringApplication() {
+ return new SpringApplication();
+ }
+
+ private Set