mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Unify use of @BootStrapWith
Update @IntegrationTest to use @BootstrapWith rather than an explicitly defined set of test execution listeners. Also introduce a new @SpringApplicationTest annotation that is similar to @SpringApplicationConfiguration but a bootstrapper. Fixes gh-5230
This commit is contained in:
parent
90950cfb1c
commit
7dffb702b5
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
* <p>
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
|
@ -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<String> getDefaultTestExecutionListenerClassNames() {
|
||||
// Remove the ServletTestExecutionListener because it only deals with MockServlet
|
||||
List<String> classNames = new ArrayList<String>(
|
||||
super.getDefaultTestExecutionListenerClassNames());
|
||||
while (classNames.contains(SERVLET_LISTENER)) {
|
||||
classNames.remove(SERVLET_LISTENER);
|
||||
}
|
||||
return Collections.unmodifiableList(classNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MergedContextConfiguration processMergedContextConfiguration(
|
||||
MergedContextConfiguration mergedConfig) {
|
||||
mergedConfig = super.processMergedContextConfiguration(mergedConfig);
|
||||
WebAppConfiguration webAppConfiguration = AnnotatedElementUtils
|
||||
.getMergedAnnotation(mergedConfig.getTestClass(),
|
||||
WebAppConfiguration.class);
|
||||
if (webAppConfiguration != null) {
|
||||
mergedConfig = new WebMergedContextConfiguration(mergedConfig,
|
||||
webAppConfiguration.value());
|
||||
}
|
||||
return mergedConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processPropertySourceProperties(
|
||||
MergedContextConfiguration mergedConfig,
|
||||
List<String> propertySourceProperties) {
|
||||
IntegrationTest annotation = AnnotatedElementUtils
|
||||
.getMergedAnnotation(mergedConfig.getTestClass(), IntegrationTest.class);
|
||||
propertySourceProperties.addAll(Arrays.asList(annotation.value()));
|
||||
}
|
||||
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
@ -34,9 +34,20 @@ import org.springframework.test.context.ContextConfiguration;
|
||||
* <p>
|
||||
* Similar to the standard {@link ContextConfiguration @ContextConfiguration} but uses
|
||||
* Spring Boot's {@link SpringApplicationContextLoader}.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
|
@ -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.
|
||||
* <p>
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li>{@link SpringApplicationTest @SpringApplicationTest} - For non-web applications, or
|
||||
* web-applications running under a mock servlet environment</li>
|
||||
* <li>{@link IntegrationTest @IntegrationTest} - To integration test non-web applications
|
||||
* </li>
|
||||
* <li>
|
||||
* {@link org.springframework.boot.test.context.web.WebIntegrationTest @WebIntegrationTest}
|
||||
* - To integration test web applications (i.e. listening on normal ports).</li>
|
||||
* </ul>
|
||||
* 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(...)}).
|
||||
* <p>
|
||||
* 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<String> INTEGRATION_TEST_ANNOTATIONS;
|
||||
|
||||
static {
|
||||
Set<String> annotations = new LinkedHashSet<String>();
|
||||
annotations.add("org.springframework.boot.test.context.IntegrationTest");
|
||||
annotations.add("org.springframework.boot.test.context.web.WebIntegrationTest");
|
||||
annotations.add("org.springframework.boot.test.IntegrationTest");
|
||||
annotations.add("org.springframework.boot.test.WebIntegrationTest");
|
||||
INTEGRATION_TEST_ANNOTATIONS = Collections.unmodifiableSet(annotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationContext loadContext(final MergedContextConfiguration config)
|
||||
public ApplicationContext loadContext(MergedContextConfiguration config)
|
||||
throws Exception {
|
||||
assertValidAnnotations(config.getTestClass());
|
||||
SpringApplication application = getSpringApplication();
|
||||
application.setMainApplicationClass(config.getTestClass());
|
||||
application.setSources(getSources(config));
|
||||
@ -95,7 +109,9 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
||||
List<ApplicationContextInitializer<?>> initializers = getInitializers(config,
|
||||
application);
|
||||
if (config instanceof WebMergedContextConfiguration) {
|
||||
new WebConfigurer().configure(config, application, initializers);
|
||||
application.setWebEnvironment(true);
|
||||
WebConfigurer configurer = new WebConfigurer(isIntegrationTest(config));
|
||||
configurer.configure(config, application, initializers);
|
||||
}
|
||||
else {
|
||||
application.setWebEnvironment(false);
|
||||
@ -105,15 +121,6 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
||||
return context;
|
||||
}
|
||||
|
||||
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
|
||||
@ -147,7 +154,7 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
||||
disableJmx(properties);
|
||||
properties.putAll(TestPropertySourceUtils
|
||||
.convertInlinedPropertiesToMap(config.getPropertySourceProperties()));
|
||||
if (!TestAnnotations.isIntegrationTest(config)) {
|
||||
if (!isIntegrationTest(config)) {
|
||||
properties.putAll(getDefaultEnvironmentProperties());
|
||||
}
|
||||
return properties;
|
||||
@ -185,6 +192,21 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
||||
return initializers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the test is a full integration test or not. By default this method checks
|
||||
* for well known integration test annotations.
|
||||
* @param config the merged context configuration
|
||||
* @return if the test is an integration test
|
||||
*/
|
||||
protected boolean isIntegrationTest(MergedContextConfiguration config) {
|
||||
for (String annotation : INTEGRATION_TEST_ANNOTATIONS) {
|
||||
if (AnnotatedElementUtils.isAnnotated(config.getTestClass(), annotation)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processContextConfiguration(
|
||||
ContextConfigurationAttributes configAttributes) {
|
||||
@ -233,10 +255,16 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
||||
|
||||
private static final Class<GenericWebApplicationContext> WEB_CONTEXT_CLASS = GenericWebApplicationContext.class;
|
||||
|
||||
private final boolean integrationTest;
|
||||
|
||||
WebConfigurer(boolean integrationTest) {
|
||||
this.integrationTest = integrationTest;
|
||||
}
|
||||
|
||||
void configure(MergedContextConfiguration configuration,
|
||||
SpringApplication application,
|
||||
List<ApplicationContextInitializer<?>> initializers) {
|
||||
if (!TestAnnotations.isIntegrationTest(configuration)) {
|
||||
if (!this.integrationTest) {
|
||||
WebMergedContextConfiguration webConfiguration = (WebMergedContextConfiguration) configuration;
|
||||
addMockServletContext(initializers, webConfiguration);
|
||||
application.setApplicationContextClass(WEB_CONTEXT_CLASS);
|
||||
@ -248,8 +276,8 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
||||
WebMergedContextConfiguration webConfiguration) {
|
||||
SpringBootMockServletContext servletContext = new SpringBootMockServletContext(
|
||||
webConfiguration.getResourceBasePath());
|
||||
initializers.add(0,
|
||||
new ServletContextApplicationContextInitializer(servletContext));
|
||||
initializers.add(0, new ServletContextApplicationContextInitializer(
|
||||
servletContext, true));
|
||||
}
|
||||
|
||||
}
|
||||
@ -274,22 +302,6 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
||||
|
||||
}
|
||||
|
||||
private static class TestAnnotations {
|
||||
|
||||
public static boolean isIntegrationTest(
|
||||
MergedContextConfiguration configuration) {
|
||||
return (hasAnnotation(configuration, IntegrationTest.class)
|
||||
|| hasAnnotation(configuration, WebIntegrationTest.class));
|
||||
}
|
||||
|
||||
private static boolean hasAnnotation(MergedContextConfiguration configuration,
|
||||
Class<? extends Annotation> annotation) {
|
||||
return (AnnotationUtils.findAnnotation(configuration.getTestClass(),
|
||||
annotation) != null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts a {@link ContextCustomizer} to a {@link ApplicationContextInitializer} so
|
||||
* that it can be triggered via {@link SpringApplication}.
|
||||
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.ApplicationContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.BootstrapWith;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* Test class annotation signifying that the tests are 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.
|
||||
* <p>
|
||||
* 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 {};
|
||||
|
||||
}
|
@ -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<String> propertySourceProperties) {
|
||||
SpringApplicationTest annotation = AnnotatedElementUtils.getMergedAnnotation(
|
||||
mergedConfig.getTestClass(), SpringApplicationTest.class);
|
||||
propertySourceProperties.addAll(Arrays.asList(annotation.value()));
|
||||
}
|
||||
|
||||
}
|
@ -23,27 +23,43 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
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.context.ApplicationContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.BootstrapWith;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
/**
|
||||
* Test class annotation signifying that the tests are "web integration tests" and
|
||||
* Test class annotation signifying that the tests are "web integration tests" for a
|
||||
* {@link org.springframework.boot.SpringApplication Spring Boot Application} and
|
||||
* therefore require full startup in the same way as a production application (listening
|
||||
* on normal ports). Normally used in conjunction with
|
||||
* {@code @SpringApplicationConfiguration},
|
||||
* on normal ports. 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.
|
||||
* <p>
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
|
@ -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(
|
||||
mergedConfig.getTestClass(), WebIntegrationTest.class);
|
||||
if (annotation != null) {
|
||||
mergedConfig = new WebMergedContextConfiguration(mergedConfig, null);
|
||||
MergedContextConfigurationProperties properties = new MergedContextConfigurationProperties(
|
||||
mergedConfig);
|
||||
if (annotation.randomPort()) {
|
||||
properties.add(annotation.value(), "server.port:0");
|
||||
}
|
||||
else {
|
||||
properties.add(annotation.value());
|
||||
}
|
||||
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<String> propertySourceProperties) {
|
||||
WebIntegrationTest annotation = AnnotatedElementUtils.getMergedAnnotation(
|
||||
mergedConfig.getTestClass(), WebIntegrationTest.class);
|
||||
propertySourceProperties.addAll(Arrays.asList(annotation.value()));
|
||||
if (annotation.randomPort()) {
|
||||
propertySourceProperties.add("server.port=0");
|
||||
}
|
||||
return mergedConfig;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 javax.servlet.ServletContext;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringApplicationTest}
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringApplicationTest("value=123")
|
||||
@DirtiesContext
|
||||
public class SpringApplicationTestTests {
|
||||
|
||||
@Value("${value}")
|
||||
private int value = 0;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private ServletContext servletContext;
|
||||
|
||||
@Test
|
||||
public void annotationAttributesOverridePropertiesFile() throws Exception {
|
||||
assertThat(this.value).isEqualTo(123);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWebApplicationContextIsSet() {
|
||||
WebApplicationContext fromServletContext = WebApplicationContextUtils
|
||||
.getWebApplicationContext(this.servletContext);
|
||||
assertThat(fromServletContext).isSameAs(this.context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setsRequestContextHolder() throws Exception {
|
||||
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
|
||||
assertThat(attributes).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
protected static class Config {
|
||||
|
||||
@Bean
|
||||
public static PropertySourcesPlaceholderConfigurer propertyPlaceholder() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2012 the original author or authors.
|
||||
* Copyright 2010-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.
|
||||
@ -18,14 +18,17 @@ package org.springframework.boot.context.web;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link ApplicationContextInitializer} for setting the servlet context.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ServletContextApplicationContextInitializer implements
|
||||
ApplicationContextInitializer<ConfigurableWebApplicationContext>, Ordered {
|
||||
@ -34,12 +37,27 @@ public class ServletContextApplicationContextInitializer implements
|
||||
|
||||
private final ServletContext servletContext;
|
||||
|
||||
private final boolean addApplicationContextAttribute;
|
||||
|
||||
/**
|
||||
* Create a new {@link ServletContextApplicationContextInitializer} instance.
|
||||
* @param servletContext the servlet that should be ultimately set.
|
||||
*/
|
||||
public ServletContextApplicationContextInitializer(ServletContext servletContext) {
|
||||
this(servletContext, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ServletContextApplicationContextInitializer} instance.
|
||||
* @param servletContext the servlet that should be ultimately set.
|
||||
* @param addApplicationContextAttribute if the {@link ApplicationContext} should be
|
||||
* stored as an attribute in the {@link ServletContext}
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public ServletContextApplicationContextInitializer(ServletContext servletContext,
|
||||
boolean addApplicationContextAttribute) {
|
||||
this.servletContext = servletContext;
|
||||
this.addApplicationContextAttribute = addApplicationContextAttribute;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
@ -54,6 +72,12 @@ public class ServletContextApplicationContextInitializer implements
|
||||
@Override
|
||||
public void initialize(ConfigurableWebApplicationContext applicationContext) {
|
||||
applicationContext.setServletContext(this.servletContext);
|
||||
if (this.addApplicationContextAttribute) {
|
||||
this.servletContext.setAttribute(
|
||||
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
|
||||
applicationContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user