提交 9fd36ae1 编写于 作者: S Sam Brannen

[WIP] Introduce @TestConfiguration

See gh-19930
上级 5a87cd05
/*
* Copyright 2002-2019 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
*
* https://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.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;
/**
* {@code @TestConfiguration} is a type-level annotation that is used to configure
* how Spring test configuration annotations are processed within enclosing
* class hierarchies (i.e., for <em>inner</em> test classes).
*
* <p>If {@code @TestConfiguration} is not <em>present</em> or <em>meta-present</em>
* on a test class, configuration from the test class will not propagate to
* inner test classes (see {@value EnclosingConfiguration#OVERRIDE}). Consequently,
* inner test classes will have to declare their own Spring test configuration
* annotations. If you wish for an inner test class to inherit configuration from
* its enclosing class, annotate the enclosing class with
* {@code @TestConfiguration(EnclosingConfiguration.INHERIT)}.
*
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
* <em>composed annotations</em>.
*
* <p>As of Spring Framework 5.2, the use of this annotation typically only makes
* sense in conjunction with {@link org.junit.jupiter.api.Nested @Nested} test
* classes in JUnit Jupiter.
*
* @author Sam Brannen
* @since 5.2
* @see EnclosingConfiguration#INHERIT
* @see EnclosingConfiguration#OVERRIDE
* @see ContextConfiguration @ContextConfiguration
* @see ContextHierarchy @ContextHierarchy
* @see ActiveProfiles @ActiveProfiles
* @see TestPropertySource @TestPropertySource
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface TestConfiguration {
/**
* Configures the {@link EnclosingConfiguration} mode.
*/
EnclosingConfiguration value();
/**
* Enumeration of <em>modes</em> that dictate how test configuration from
* enclosing classes is processed for inner test classes.
*/
enum EnclosingConfiguration {
/**
* Indicates that test configuration for an inner test class should be
* <em>inherited</em> from its {@linkplain Class#getEnclosingClass()
* enclosing class}, as if the enclosing class were a superclass.
*/
INHERIT,
/**
* Indicates that test configuration for an inner test class should
* <em>override</em> configuration from its
* {@linkplain Class#getEnclosingClass() enclosing class}.
*/
OVERRIDE
}
}
......@@ -16,7 +16,6 @@
package org.springframework.test.context.support;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
......@@ -35,6 +34,8 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.SmartContextLoader;
import org.springframework.test.context.TestConfiguration;
import org.springframework.test.context.TestConfiguration.EnclosingConfiguration;
import org.springframework.test.util.MetaAnnotationUtils.UntypedAnnotationDescriptor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
......@@ -240,8 +241,7 @@ abstract class ContextLoaderUtils {
Assert.notNull(testClass, "Class must not be null");
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
MergedAnnotations mergedAnnotations = MergedAnnotations.from(testClass,
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES);
MergedAnnotations mergedAnnotations = MergedAnnotations.from(testClass, getSearchStrategy(testClass));
Assert.isTrue(mergedAnnotations.isPresent(annotationType), () -> String.format(
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]",
annotationType.getName(), testClass.getName()));
......@@ -252,6 +252,18 @@ abstract class ContextLoaderUtils {
return attributesList;
}
private static SearchStrategy getSearchStrategy(Class<?> testClass) {
EnclosingConfiguration enclosingConfiguration =
MergedAnnotations.from(testClass, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES)
.stream(TestConfiguration.class)
.map(mergedAnnotation -> mergedAnnotation.getEnum("value", EnclosingConfiguration.class))
.findFirst()
.orElse(EnclosingConfiguration.OVERRIDE);
return (enclosingConfiguration == EnclosingConfiguration.INHERIT ?
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES :
SearchStrategy.TYPE_HIERARCHY);
}
private static void resolveContextConfigurationAttributes(List<ContextConfigurationAttributes> attributesList,
MergedAnnotation<ContextConfiguration> mergedAnnotation) {
......
......@@ -36,6 +36,8 @@ import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.ContextLoader;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.TestConfiguration;
import org.springframework.test.context.TestConfiguration.EnclosingConfiguration;
import org.springframework.test.context.TestContextBootstrapper;
import org.springframework.test.context.web.WebAppConfiguration;
......@@ -231,6 +233,7 @@ abstract class AbstractContextConfigurationUtilsTests {
@ContextConfiguration(classes = FooConfig.class, loader = AnnotationConfigContextLoader.class)
@ActiveProfiles("foo")
@TestConfiguration(EnclosingConfiguration.INHERIT)
static class OuterTestCase {
class NestedTestCaseWithInheritedConfig {
......@@ -252,6 +255,7 @@ abstract class AbstractContextConfigurationUtilsTests {
@ContextConfiguration(classes = FooConfig.class, loader = AnnotationConfigContextLoader.class, name = "foo"), //
@ContextConfiguration(classes = BarConfig.class, loader = AnnotationConfigContextLoader.class)//
})
@TestConfiguration(EnclosingConfiguration.INHERIT)
static class ContextHierarchyOuterTestCase {
class NestedTestCaseWithInheritedConfig {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册