Provide meta-annotation support in the TCF
Spring 3.0 already allows component stereotypes to be used in a meta-annotation fashion, for example by creating a custom @TransactionalService stereotype annotation which combines @Transactional and @Service in a single, reusable, application-specific annotation. However, the Spring TestContext Framework (TCF) currently does not provide any support for test-related annotations to be used as meta-annotations. This commit overhauls the TCF with regard to how annotations are retrieved and adds explicit support for the following annotations to be used as meta-annotations in conjunction with the TCF. - @ContextConfiguration - @ContextHierarchy - @ActiveProfiles - @DirtiesContext - @IfProfileValue - @ProfileValueSourceConfiguration - @BeforeTransaction - @AfterTransaction - @TransactionConfiguration - @Rollback - @TestExecutionListeners - @Repeat - @Timed - @WebAppConfiguration Note that meta-annotation support for @Transactional was already available prior to this commit. The following is a summary of the major changes included in this commit. - Now using AnnotationUtils.getAnnotation() instead of Class.getAnnotation() where appropriate in the TestContext Framework. - Now using AnnotationUtils.findAnnotation() instead of Class.isAnnotationPresent() where appropriate in the TestContext Framework. - Introduced findAnnotationPrefersInteracesOverLocalMetaAnnotations() in AnnotationUtilsTests in order to verify the status quo. - AnnotationUtils.findAnnotationDeclaringClass() and AnnotationUtils.findAnnotationDeclaringClassForTypes() now support meta annotations. - Introduced MetaAnnotationUtils and AnnotationDescriptor in the spring-test module. - Introduced UntypedAnnotationDescriptor in MetaAnnotationUtils. - Introduced findAnnotationDescriptorForTypes() in MetaAnnotationUtils. - ContextLoaderUtils now uses MetaAnnotationUtils for looking up @ActiveProfiles as a potential meta-annotation. - TestContextManager now uses MetaAnnotationUtils for looking up @TestExecutionListeners as a potential meta-annotation. - DirtiesContextTestExecutionListener now uses AnnotationUtils for looking up @DirtiesContext as a potential meta-annotation. - Introduced DirtiesContextTestExecutionListenerTests. - ProfileValueUtils now uses AnnotationUtils for looking up @IfProfileValue and @ProfileValueSourceConfiguration as potential meta-annotations. - @BeforeTransaction and @AfterTransaction now support ANNOTATION_TYPE as a target, allowing them to be used as meta-annotations. - TransactionalTestExecutionListener now uses AnnotationUtils for looking up @BeforeTransaction, @AfterTransaction, @Rollback, and @TransactionConfiguration as potential meta-annotations. - Introduced TransactionalTestExecutionListenerTests. - @Repeat and @Timed now support ANNOTATION_TYPE as a target, allowing them to be used as meta-annotations. - SpringJUnit4ClassRunner now uses AnnotationUtils for looking up @Repeat and @Timed as potential meta-annotations. - Moved all remaining logic for building the MergedContextConfiguration from the DefaultTestContext constructor to ContextLoaderUtils.buildMergedContextConfiguration(). - Verified meta-annotation support for @WebAppConfiguration and @ContextConfiguration. Issue: SPR-7827
This commit is contained in:
parent
56dfcd153e
commit
5e7021f3f7
|
|
@ -285,9 +285,8 @@ public abstract class AnnotationUtils {
|
|||
* <p>The standard {@link Class} API does not provide a mechanism for determining which class
|
||||
* in an inheritance hierarchy actually declares an {@link Annotation}, so we need to handle
|
||||
* this explicitly.
|
||||
* @param annotationType the Class object corresponding to the annotation type
|
||||
* @param clazz the Class object corresponding to the class on which to check for the annotation,
|
||||
* or {@code null}
|
||||
* @param annotationType the annotation class to look for, both locally and as a meta-annotation
|
||||
* @param clazz the class on which to check for the annotation, or {@code null}
|
||||
* @return the first {@link Class} in the inheritance hierarchy of the specified {@code clazz}
|
||||
* which declares an annotation for the specified {@code annotationType}, or {@code null}
|
||||
* if not found
|
||||
|
|
@ -301,8 +300,24 @@ public abstract class AnnotationUtils {
|
|||
if (clazz == null || clazz.equals(Object.class)) {
|
||||
return null;
|
||||
}
|
||||
return (isAnnotationDeclaredLocally(annotationType, clazz)) ? clazz : findAnnotationDeclaringClass(
|
||||
annotationType, clazz.getSuperclass());
|
||||
|
||||
// Declared locally?
|
||||
if (isAnnotationDeclaredLocally(annotationType, clazz)) {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
// Declared on a stereotype annotation (i.e., as a meta-annotation)?
|
||||
if (!Annotation.class.isAssignableFrom(clazz)) {
|
||||
for (Annotation stereotype : clazz.getAnnotations()) {
|
||||
Class<?> declaringClass = findAnnotationDeclaringClass(annotationType, stereotype.annotationType());
|
||||
if (declaringClass != null) {
|
||||
return declaringClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Declared on a superclass?
|
||||
return findAnnotationDeclaringClass(annotationType, clazz.getSuperclass());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -96,6 +96,18 @@ public class AnnotationUtilsTests {
|
|||
// assertNotNull(o);
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void findAnnotationPrefersInteracesOverLocalMetaAnnotations() {
|
||||
Component component = AnnotationUtils.findAnnotation(
|
||||
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, Component.class);
|
||||
|
||||
// By inspecting ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface, one
|
||||
// might expect that "meta2" should be found; however, with the current
|
||||
// implementation "meta1" will be found.
|
||||
assertNotNull(component);
|
||||
assertEquals("meta1", component.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAnnotationDeclaringClass() throws Exception {
|
||||
// no class-level annotation
|
||||
|
|
@ -133,7 +145,7 @@ public class AnnotationUtilsTests {
|
|||
assertEquals(InheritedAnnotationInterface.class,
|
||||
findAnnotationDeclaringClassForTypes(transactionalCandidateList, InheritedAnnotationInterface.class));
|
||||
assertNull(findAnnotationDeclaringClassForTypes(transactionalCandidateList,
|
||||
SubInheritedAnnotationInterface.class));
|
||||
SubInheritedAnnotationInterface.class));
|
||||
assertEquals(InheritedAnnotationClass.class,
|
||||
findAnnotationDeclaringClassForTypes(transactionalCandidateList, InheritedAnnotationClass.class));
|
||||
assertEquals(InheritedAnnotationClass.class,
|
||||
|
|
@ -288,19 +300,23 @@ public class AnnotationUtilsTests {
|
|||
|
||||
|
||||
@Component(value = "meta1")
|
||||
@Order
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Meta1 {
|
||||
}
|
||||
|
||||
@Component(value = "meta2")
|
||||
@Transactional
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Meta2 {
|
||||
}
|
||||
|
||||
@Meta1
|
||||
@Component(value = "local")
|
||||
static interface InterfaceWithMetaAnnotation {
|
||||
}
|
||||
|
||||
@Meta2
|
||||
static class HasLocalAndMetaComponentAnnotation {
|
||||
static class ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface implements InterfaceWithMetaAnnotation {
|
||||
}
|
||||
|
||||
public static interface AnnotatedInterface {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -25,6 +25,8 @@ import org.springframework.util.Assert;
|
|||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
|
||||
/**
|
||||
* General utility methods for working with <em>profile values</em>.
|
||||
*
|
||||
|
|
@ -63,7 +65,7 @@ public abstract class ProfileValueUtils {
|
|||
Assert.notNull(testClass, "testClass must not be null");
|
||||
|
||||
Class<ProfileValueSourceConfiguration> annotationType = ProfileValueSourceConfiguration.class;
|
||||
ProfileValueSourceConfiguration config = testClass.getAnnotation(annotationType);
|
||||
ProfileValueSourceConfiguration config = findAnnotation(testClass, annotationType);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved @ProfileValueSourceConfiguration [" + config + "] for test class ["
|
||||
+ testClass.getName() + "]");
|
||||
|
|
@ -114,7 +116,7 @@ public abstract class ProfileValueUtils {
|
|||
* environment
|
||||
*/
|
||||
public static boolean isTestEnabledInThisEnvironment(Class<?> testClass) {
|
||||
IfProfileValue ifProfileValue = testClass.getAnnotation(IfProfileValue.class);
|
||||
IfProfileValue ifProfileValue = findAnnotation(testClass, IfProfileValue.class);
|
||||
return isTestEnabledInThisEnvironment(retrieveProfileValueSource(testClass), ifProfileValue);
|
||||
}
|
||||
|
||||
|
|
@ -157,11 +159,11 @@ public abstract class ProfileValueUtils {
|
|||
public static boolean isTestEnabledInThisEnvironment(ProfileValueSource profileValueSource, Method testMethod,
|
||||
Class<?> testClass) {
|
||||
|
||||
IfProfileValue ifProfileValue = testClass.getAnnotation(IfProfileValue.class);
|
||||
IfProfileValue ifProfileValue = findAnnotation(testClass, IfProfileValue.class);
|
||||
boolean classLevelEnabled = isTestEnabledInThisEnvironment(profileValueSource, ifProfileValue);
|
||||
|
||||
if (classLevelEnabled) {
|
||||
ifProfileValue = testMethod.getAnnotation(IfProfileValue.class);
|
||||
ifProfileValue = findAnnotation(testMethod, IfProfileValue.class);
|
||||
return isTestEnabledInThisEnvironment(profileValueSource, ifProfileValue);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,25 +17,27 @@
|
|||
package org.springframework.test.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* Test annotation to indicate that a test method should be invoked repeatedly.
|
||||
* <p />
|
||||
* Note that the scope of execution to be repeated includes execution of the
|
||||
*
|
||||
* <p>Note that the scope of execution to be repeated includes execution of the
|
||||
* test method itself as well as any <em>set up</em> or <em>tear down</em> of
|
||||
* the test fixture.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
* @since 2.0
|
||||
* @see Timed
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RUNTIME)
|
||||
@Target({ METHOD, ANNOTATION_TYPE })
|
||||
public @interface Repeat {
|
||||
|
||||
int value() default 1;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,25 +17,22 @@
|
|||
package org.springframework.test.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Test-specific annotation to indicate that a test method has to finish
|
||||
* execution in a {@link #millis() specified time period}.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the text execution takes longer than the specified time period, then the
|
||||
* test is to be considered failed.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the time period includes execution of the test method itself, any
|
||||
* {@link Repeat repetitions} of the test, and any <em>set up</em> or
|
||||
*
|
||||
* <p>If the text execution takes longer than the specified time period, then
|
||||
* the test is to be considered failed.
|
||||
*
|
||||
* <p>Note that the time period includes execution of the test method itself,
|
||||
* any {@link Repeat repetitions} of the test, and any <em>set up</em> or
|
||||
* <em>tear down</em> of the test fixture.
|
||||
* </p>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
|
|
@ -43,8 +40,8 @@ import java.lang.annotation.Target;
|
|||
* @see Repeat
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RUNTIME)
|
||||
@Target({ METHOD, ANNOTATION_TYPE })
|
||||
public @interface Timed {
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.context.MetaAnnotationUtils.AnnotationDescriptor;
|
||||
import org.springframework.test.context.MetaAnnotationUtils.UntypedAnnotationDescriptor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
|
@ -39,6 +41,7 @@ import org.springframework.util.StringUtils;
|
|||
|
||||
import static org.springframework.beans.BeanUtils.*;
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
import static org.springframework.test.context.MetaAnnotationUtils.*;
|
||||
|
||||
/**
|
||||
* Utility methods for working with {@link ContextLoader ContextLoaders} and
|
||||
|
|
@ -108,7 +111,7 @@ abstract class ContextLoaderUtils {
|
|||
if (!StringUtils.hasText(defaultContextLoaderClassName)) {
|
||||
Class<? extends Annotation> webAppConfigClass = loadWebAppConfigurationClass();
|
||||
defaultContextLoaderClassName = webAppConfigClass != null
|
||||
&& testClass.isAnnotationPresent(webAppConfigClass) ? DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME
|
||||
&& findAnnotation(testClass, webAppConfigClass) != null ? DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME
|
||||
: DEFAULT_CONTEXT_LOADER_CLASS_NAME;
|
||||
}
|
||||
|
||||
|
|
@ -245,29 +248,32 @@ abstract class ContextLoaderUtils {
|
|||
* @see #buildContextHierarchyMap(Class)
|
||||
* @see #resolveContextConfigurationAttributes(Class)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<List<ContextConfigurationAttributes>> resolveContextHierarchyAttributes(Class<?> testClass) {
|
||||
Assert.notNull(testClass, "Class must not be null");
|
||||
|
||||
final Class<ContextConfiguration> contextConfigType = ContextConfiguration.class;
|
||||
final Class<ContextHierarchy> contextHierarchyType = ContextHierarchy.class;
|
||||
final List<Class<? extends Annotation>> annotationTypes = Arrays.asList(contextConfigType, contextHierarchyType);
|
||||
|
||||
final List<List<ContextConfigurationAttributes>> hierarchyAttributes = new ArrayList<List<ContextConfigurationAttributes>>();
|
||||
|
||||
Class<?> declaringClass = findAnnotationDeclaringClassForTypes(annotationTypes, testClass);
|
||||
Assert.notNull(declaringClass, String.format(
|
||||
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(testClass, contextConfigType,
|
||||
contextHierarchyType);
|
||||
Assert.notNull(descriptor, String.format(
|
||||
"Could not find an 'annotation declaring class' for annotation type [%s] or [%s] and test class [%s]",
|
||||
contextConfigType.getName(), contextHierarchyType.getName(), testClass.getName()));
|
||||
|
||||
while (declaringClass != null) {
|
||||
while (descriptor != null) {
|
||||
Class<?> rootDeclaringClass = descriptor.getDeclaringClass();
|
||||
Class<?> declaringClass = (descriptor.getStereotype() != null) ? descriptor.getStereotypeType()
|
||||
: rootDeclaringClass;
|
||||
|
||||
boolean contextConfigDeclaredLocally = isAnnotationDeclaredLocally(contextConfigType, declaringClass);
|
||||
boolean contextHierarchyDeclaredLocally = isAnnotationDeclaredLocally(contextHierarchyType, declaringClass);
|
||||
|
||||
if (contextConfigDeclaredLocally && contextHierarchyDeclaredLocally) {
|
||||
String msg = String.format("Test class [%s] has been configured with both @ContextConfiguration "
|
||||
+ "and @ContextHierarchy as class-level annotations. Only one of these annotations may "
|
||||
+ "be declared as a top-level annotation per test class.", declaringClass.getName());
|
||||
+ "and @ContextHierarchy. Only one of these annotations may be declared on a test class "
|
||||
+ "or custom stereotype annotation.", rootDeclaringClass.getName());
|
||||
logger.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
|
|
@ -275,12 +281,12 @@ abstract class ContextLoaderUtils {
|
|||
final List<ContextConfigurationAttributes> configAttributesList = new ArrayList<ContextConfigurationAttributes>();
|
||||
|
||||
if (contextConfigDeclaredLocally) {
|
||||
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(contextConfigType);
|
||||
ContextConfiguration contextConfiguration = getAnnotation(declaringClass, contextConfigType);
|
||||
convertContextConfigToConfigAttributesAndAddToList(contextConfiguration, declaringClass,
|
||||
configAttributesList);
|
||||
}
|
||||
else if (contextHierarchyDeclaredLocally) {
|
||||
ContextHierarchy contextHierarchy = declaringClass.getAnnotation(contextHierarchyType);
|
||||
ContextHierarchy contextHierarchy = getAnnotation(declaringClass, contextHierarchyType);
|
||||
for (ContextConfiguration contextConfiguration : contextHierarchy.value()) {
|
||||
convertContextConfigToConfigAttributesAndAddToList(contextConfiguration, declaringClass,
|
||||
configAttributesList);
|
||||
|
|
@ -289,14 +295,15 @@ abstract class ContextLoaderUtils {
|
|||
else {
|
||||
// This should theoretically actually never happen...
|
||||
String msg = String.format("Test class [%s] has been configured with neither @ContextConfiguration "
|
||||
+ "nor @ContextHierarchy as a class-level annotation.", declaringClass.getName());
|
||||
+ "nor @ContextHierarchy as a class-level annotation.", rootDeclaringClass.getName());
|
||||
logger.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
|
||||
hierarchyAttributes.add(0, configAttributesList);
|
||||
|
||||
declaringClass = findAnnotationDeclaringClassForTypes(annotationTypes, declaringClass.getSuperclass());
|
||||
descriptor = findAnnotationDescriptorForTypes(rootDeclaringClass.getSuperclass(), contextConfigType,
|
||||
contextHierarchyType);
|
||||
}
|
||||
|
||||
return hierarchyAttributes;
|
||||
|
|
@ -391,15 +398,20 @@ abstract class ContextLoaderUtils {
|
|||
final List<ContextConfigurationAttributes> attributesList = new ArrayList<ContextConfigurationAttributes>();
|
||||
|
||||
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
|
||||
Class<?> declaringClass = findAnnotationDeclaringClass(annotationType, testClass);
|
||||
Assert.notNull(declaringClass, String.format(
|
||||
|
||||
AnnotationDescriptor<ContextConfiguration> descriptor = findAnnotationDescriptor(testClass, annotationType);
|
||||
Assert.notNull(descriptor, String.format(
|
||||
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]",
|
||||
annotationType.getName(), testClass.getName()));
|
||||
|
||||
while (declaringClass != null) {
|
||||
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
|
||||
convertContextConfigToConfigAttributesAndAddToList(contextConfiguration, declaringClass, attributesList);
|
||||
declaringClass = findAnnotationDeclaringClass(annotationType, declaringClass.getSuperclass());
|
||||
while (descriptor != null) {
|
||||
Class<?> rootDeclaringClass = descriptor.getDeclaringClass();
|
||||
Class<?> declaringClass = (descriptor.getStereotype() != null) ? descriptor.getStereotypeType()
|
||||
: rootDeclaringClass;
|
||||
|
||||
convertContextConfigToConfigAttributesAndAddToList(descriptor.getAnnotation(), declaringClass,
|
||||
attributesList);
|
||||
descriptor = findAnnotationDescriptor(rootDeclaringClass.getSuperclass(), annotationType);
|
||||
}
|
||||
|
||||
return attributesList;
|
||||
|
|
@ -465,9 +477,10 @@ abstract class ContextLoaderUtils {
|
|||
Assert.notNull(testClass, "Class must not be null");
|
||||
|
||||
Class<ActiveProfiles> annotationType = ActiveProfiles.class;
|
||||
Class<?> declaringClass = findAnnotationDeclaringClass(annotationType, testClass);
|
||||
|
||||
if (declaringClass == null && logger.isDebugEnabled()) {
|
||||
AnnotationDescriptor<ActiveProfiles> descriptor = findAnnotationDescriptor(testClass, annotationType);
|
||||
|
||||
if (descriptor == null && logger.isDebugEnabled()) {
|
||||
logger.debug(String.format(
|
||||
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]",
|
||||
annotationType.getName(), testClass.getName()));
|
||||
|
|
@ -475,8 +488,12 @@ abstract class ContextLoaderUtils {
|
|||
|
||||
final Set<String> activeProfiles = new HashSet<String>();
|
||||
|
||||
while (declaringClass != null) {
|
||||
ActiveProfiles annotation = declaringClass.getAnnotation(annotationType);
|
||||
while (descriptor != null) {
|
||||
Class<?> rootDeclaringClass = descriptor.getDeclaringClass();
|
||||
Class<?> declaringClass = (descriptor.getStereotype() != null) ? descriptor.getStereotypeType()
|
||||
: rootDeclaringClass;
|
||||
|
||||
ActiveProfiles annotation = descriptor.getAnnotation();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(String.format("Retrieved @ActiveProfiles [%s] for declaring class [%s].", annotation,
|
||||
declaringClass.getName()));
|
||||
|
|
@ -521,8 +538,8 @@ abstract class ContextLoaderUtils {
|
|||
}
|
||||
}
|
||||
|
||||
declaringClass = annotation.inheritProfiles() ? findAnnotationDeclaringClass(annotationType,
|
||||
declaringClass.getSuperclass()) : null;
|
||||
descriptor = annotation.inheritProfiles() ? findAnnotationDescriptor(rootDeclaringClass.getSuperclass(),
|
||||
annotationType) : null;
|
||||
}
|
||||
|
||||
return StringUtils.toStringArray(activeProfiles);
|
||||
|
|
@ -582,11 +599,20 @@ abstract class ContextLoaderUtils {
|
|||
* @see #buildContextHierarchyMap(Class)
|
||||
* @see #buildMergedContextConfiguration(Class, List, String, MergedContextConfiguration, CacheAwareContextLoaderDelegate)
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
@SuppressWarnings({ "javadoc", "unchecked" })
|
||||
static MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass,
|
||||
String defaultContextLoaderClassName, CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate) {
|
||||
|
||||
if (testClass.isAnnotationPresent(ContextHierarchy.class)) {
|
||||
if (findAnnotationDescriptorForTypes(testClass, ContextConfiguration.class, ContextHierarchy.class) == null) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format(
|
||||
"Neither @ContextConfiguration nor @ContextHierarchy found for test class [%s]",
|
||||
testClass.getName()));
|
||||
}
|
||||
return new MergedContextConfiguration(testClass, null, null, null, null);
|
||||
}
|
||||
|
||||
if (findAnnotation(testClass, ContextHierarchy.class) != null) {
|
||||
Map<String, List<ContextConfigurationAttributes>> hierarchyMap = buildContextHierarchyMap(testClass);
|
||||
|
||||
MergedContextConfiguration parentConfig = null;
|
||||
|
|
@ -729,28 +755,32 @@ abstract class ContextLoaderUtils {
|
|||
CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, MergedContextConfiguration parentConfig) {
|
||||
|
||||
Class<? extends Annotation> webAppConfigClass = loadWebAppConfigurationClass();
|
||||
if (webAppConfigClass != null) {
|
||||
|
||||
if (webAppConfigClass != null && testClass.isAnnotationPresent(webAppConfigClass)) {
|
||||
Annotation annotation = testClass.getAnnotation(webAppConfigClass);
|
||||
String resourceBasePath = (String) AnnotationUtils.getValue(annotation);
|
||||
Annotation annotation = findAnnotation(testClass, webAppConfigClass);
|
||||
if (annotation != null) {
|
||||
|
||||
try {
|
||||
Class<? extends MergedContextConfiguration> webMergedConfigClass = (Class<? extends MergedContextConfiguration>) ClassUtils.forName(
|
||||
WEB_MERGED_CONTEXT_CONFIGURATION_CLASS_NAME, ContextLoaderUtils.class.getClassLoader());
|
||||
String resourceBasePath = (String) AnnotationUtils.getValue(annotation);
|
||||
|
||||
Constructor<? extends MergedContextConfiguration> constructor = ClassUtils.getConstructorIfAvailable(
|
||||
webMergedConfigClass, Class.class, String[].class, Class[].class, Set.class, String[].class,
|
||||
String.class, ContextLoader.class, CacheAwareContextLoaderDelegate.class,
|
||||
MergedContextConfiguration.class);
|
||||
try {
|
||||
Class<? extends MergedContextConfiguration> webMergedConfigClass = (Class<? extends MergedContextConfiguration>) ClassUtils.forName(
|
||||
WEB_MERGED_CONTEXT_CONFIGURATION_CLASS_NAME, ContextLoaderUtils.class.getClassLoader());
|
||||
|
||||
if (constructor != null) {
|
||||
return instantiateClass(constructor, testClass, locations, classes, initializerClasses,
|
||||
activeProfiles, resourceBasePath, contextLoader, cacheAwareContextLoaderDelegate, parentConfig);
|
||||
Constructor<? extends MergedContextConfiguration> constructor = ClassUtils.getConstructorIfAvailable(
|
||||
webMergedConfigClass, Class.class, String[].class, Class[].class, Set.class, String[].class,
|
||||
String.class, ContextLoader.class, CacheAwareContextLoaderDelegate.class,
|
||||
MergedContextConfiguration.class);
|
||||
|
||||
if (constructor != null) {
|
||||
return instantiateClass(constructor, testClass, locations, classes, initializerClasses,
|
||||
activeProfiles, resourceBasePath, contextLoader, cacheAwareContextLoaderDelegate,
|
||||
parentConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not instantiate [" + WEB_MERGED_CONTEXT_CONFIGURATION_CLASS_NAME + "].", t);
|
||||
catch (Throwable t) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not instantiate [" + WEB_MERGED_CONTEXT_CONFIGURATION_CLASS_NAME + "].", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,6 @@ package org.springframework.test.context;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.AttributeAccessorSupport;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
|
@ -43,8 +40,6 @@ class DefaultTestContext extends AttributeAccessorSupport implements TestContext
|
|||
|
||||
private static final long serialVersionUID = -5827157174866681233L;
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DefaultTestContext.class);
|
||||
|
||||
private final ContextCache contextCache;
|
||||
|
||||
private final CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate;
|
||||
|
|
@ -95,24 +90,8 @@ class DefaultTestContext extends AttributeAccessorSupport implements TestContext
|
|||
this.testClass = testClass;
|
||||
this.contextCache = contextCache;
|
||||
this.cacheAwareContextLoaderDelegate = new CacheAwareContextLoaderDelegate(contextCache);
|
||||
|
||||
MergedContextConfiguration mergedContextConfiguration;
|
||||
|
||||
if (testClass.isAnnotationPresent(ContextConfiguration.class)
|
||||
|| testClass.isAnnotationPresent(ContextHierarchy.class)) {
|
||||
mergedContextConfiguration = ContextLoaderUtils.buildMergedContextConfiguration(testClass,
|
||||
defaultContextLoaderClassName, cacheAwareContextLoaderDelegate);
|
||||
}
|
||||
else {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format(
|
||||
"Neither @ContextConfiguration nor @ContextHierarchy found for test class [%s]",
|
||||
testClass.getName()));
|
||||
}
|
||||
mergedContextConfiguration = new MergedContextConfiguration(testClass, null, null, null, null);
|
||||
}
|
||||
|
||||
this.mergedContextConfiguration = mergedContextConfiguration;
|
||||
this.mergedContextConfiguration = ContextLoaderUtils.buildMergedContextConfiguration(testClass,
|
||||
defaultContextLoaderClassName, cacheAwareContextLoaderDelegate);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.test.context;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
|
||||
/**
|
||||
* TODO Document MetaAnnotationUtils.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
abstract class MetaAnnotationUtils {
|
||||
|
||||
private MetaAnnotationUtils() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document findAnnotationDescriptor().
|
||||
*
|
||||
* @param clazz the class to look for annotations on
|
||||
* @param annotationType the annotation class to look for, both locally and
|
||||
* as a meta-annotation
|
||||
* @return the corresponding annotation descriptor if the annotation was found;
|
||||
* otherwise {@code null}
|
||||
*/
|
||||
public static <T extends Annotation> AnnotationDescriptor<T> findAnnotationDescriptor(Class<?> clazz,
|
||||
Class<T> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null");
|
||||
|
||||
if (clazz == null || clazz.equals(Object.class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Declared locally?
|
||||
if (isAnnotationDeclaredLocally(annotationType, clazz)) {
|
||||
return new AnnotationDescriptor<T>(clazz, clazz.getAnnotation(annotationType));
|
||||
}
|
||||
|
||||
// Declared on a stereotype annotation (i.e., as a meta-annotation)?
|
||||
if (!Annotation.class.isAssignableFrom(clazz)) {
|
||||
for (Annotation stereotype : clazz.getAnnotations()) {
|
||||
T annotation = stereotype.annotationType().getAnnotation(annotationType);
|
||||
if (annotation != null) {
|
||||
return new AnnotationDescriptor<T>(clazz, stereotype, annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Declared on a superclass?
|
||||
return findAnnotationDescriptor(clazz.getSuperclass(), annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document findAnnotationDescriptorForTypes().
|
||||
*
|
||||
* @param clazz the class to look for annotations on
|
||||
* @param annotationTypes the types of annotations to look for, both locally
|
||||
* and as meta-annotations
|
||||
* @return the corresponding annotation descriptor if one of the annotations
|
||||
* was found; otherwise {@code null}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(Class<?> clazz,
|
||||
Class<? extends Annotation>... annotationTypes) {
|
||||
|
||||
assertNonEmptyAnnotationTypeArray(annotationTypes, "The list of annotation types must not be empty");
|
||||
|
||||
if (clazz == null || clazz.equals(Object.class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Declared locally?
|
||||
for (Class<? extends Annotation> annotationType : annotationTypes) {
|
||||
if (isAnnotationDeclaredLocally(annotationType, clazz)) {
|
||||
return new UntypedAnnotationDescriptor(clazz, clazz.getAnnotation(annotationType));
|
||||
}
|
||||
}
|
||||
|
||||
// Declared on a stereotype annotation (i.e., as a meta-annotation)?
|
||||
if (!Annotation.class.isAssignableFrom(clazz)) {
|
||||
for (Annotation stereotype : clazz.getAnnotations()) {
|
||||
for (Class<? extends Annotation> annotationType : annotationTypes) {
|
||||
Annotation annotation = stereotype.annotationType().getAnnotation(annotationType);
|
||||
if (annotation != null) {
|
||||
return new UntypedAnnotationDescriptor(clazz, stereotype, annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Declared on a superclass?
|
||||
return findAnnotationDescriptorForTypes(clazz.getSuperclass(), annotationTypes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Descriptor for an {@link Annotation}, including the {@linkplain
|
||||
* #getDeclaringClass() class} on which the annotation is <em>declared</em>
|
||||
* as well as the actual {@linkplain #getAnnotation() annotation} instance.
|
||||
*
|
||||
* <p>
|
||||
* If the annotation is used as a meta-annotation, the descriptor also includes
|
||||
* the {@linkplain #getStereotype() stereotype} on which the annotation is
|
||||
* present. In such cases, the <em>declaring class</em> is not directly
|
||||
* annotated with the annotation but rather indirectly via the stereotype.
|
||||
*
|
||||
* <p>
|
||||
* Given the following example, if we are searching for the {@code @Transactional}
|
||||
* annotation <em>on</em> the {@code TransactionalTests} class, then the
|
||||
* properties of the {@code AnnotationDescriptor} would be as follows.
|
||||
*
|
||||
* <ul>
|
||||
* <li>declaringClass: {@code TransactionalTests} class object</li>
|
||||
* <li>stereotype: {@code null}</li>
|
||||
* <li>annotation: instance of the {@code Transactional} annotation</li>
|
||||
* </ul>
|
||||
*
|
||||
* <pre style="code">
|
||||
* @Transactional
|
||||
* @ContextConfiguration({"/test-datasource.xml", "/repository-config.xml"})
|
||||
* public class TransactionalTests { }
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Given the following example, if we are searching for the {@code @Transactional}
|
||||
* annotation <em>on</em> the {@code UserRepositoryTests} class, then the
|
||||
* properties of the {@code AnnotationDescriptor} would be as follows.
|
||||
*
|
||||
* <ul>
|
||||
* <li>declaringClass: {@code UserRepositoryTests} class object</li>
|
||||
* <li>stereotype: instance of the {@code RepositoryTests} annotation</li>
|
||||
* <li>annotation: instance of the {@code Transactional} annotation</li>
|
||||
* </ul>
|
||||
*
|
||||
* <pre style="code">
|
||||
* @Transactional
|
||||
* @ContextConfiguration({"/test-datasource.xml", "/repository-config.xml"})
|
||||
* @Retention(RetentionPolicy.RUNTIME)
|
||||
* public @interface RepositoryTests { }
|
||||
*
|
||||
* @RepositoryTests
|
||||
* public class UserRepositoryTests { }
|
||||
* </pre>
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
public static class AnnotationDescriptor<T extends Annotation> {
|
||||
|
||||
private final Class<?> declaringClass;
|
||||
private final Annotation stereotype;
|
||||
private final T annotation;
|
||||
|
||||
|
||||
public AnnotationDescriptor(Class<?> declaringClass, T annotation) {
|
||||
this(declaringClass, null, annotation);
|
||||
}
|
||||
|
||||
public AnnotationDescriptor(Class<?> declaringClass, Annotation stereotype, T annotation) {
|
||||
Assert.notNull(declaringClass, "declaringClass must not be null");
|
||||
Assert.notNull(annotation, "annotation must not be null");
|
||||
|
||||
this.declaringClass = declaringClass;
|
||||
this.stereotype = stereotype;
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
public Class<?> getDeclaringClass() {
|
||||
return this.declaringClass;
|
||||
}
|
||||
|
||||
public T getAnnotation() {
|
||||
return this.annotation;
|
||||
}
|
||||
|
||||
public Class<? extends Annotation> getAnnotationType() {
|
||||
return this.annotation.annotationType();
|
||||
}
|
||||
|
||||
public Annotation getStereotype() {
|
||||
return this.stereotype;
|
||||
}
|
||||
|
||||
public Class<? extends Annotation> getStereotypeType() {
|
||||
return this.stereotype == null ? null : this.stereotype.annotationType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a textual representation of this {@code AnnotationDescriptor}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this)//
|
||||
.append("declaringClass", declaringClass)//
|
||||
.append("stereotype", stereotype)//
|
||||
.append("annotation", annotation)//
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class UntypedAnnotationDescriptor extends AnnotationDescriptor<Annotation> {
|
||||
|
||||
public UntypedAnnotationDescriptor(Class<?> declaringClass, Annotation annotation) {
|
||||
super(declaringClass, annotation);
|
||||
}
|
||||
|
||||
public UntypedAnnotationDescriptor(Class<?> declaringClass, Annotation stereotype, Annotation annotation) {
|
||||
super(declaringClass, stereotype, annotation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void assertNonEmptyAnnotationTypeArray(Class<?>[] annotationTypes, String message) {
|
||||
if (ObjectUtils.isEmpty(annotationTypes)) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
|
||||
for (Class clazz : annotationTypes) {
|
||||
if (!Annotation.class.isAssignableFrom(clazz)) {
|
||||
throw new IllegalArgumentException("Array elements must be of type Annotation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -28,10 +28,12 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.context.MetaAnnotationUtils.AnnotationDescriptor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import static org.springframework.test.context.MetaAnnotationUtils.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@code TestContextManager} is the main entry point into the
|
||||
|
|
@ -174,11 +176,13 @@ public class TestContextManager {
|
|||
Assert.notNull(clazz, "Class must not be null");
|
||||
Class<TestExecutionListeners> annotationType = TestExecutionListeners.class;
|
||||
List<Class<? extends TestExecutionListener>> classesList = new ArrayList<Class<? extends TestExecutionListener>>();
|
||||
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
|
||||
|
||||
AnnotationDescriptor<TestExecutionListeners> descriptor = findAnnotationDescriptor(clazz, annotationType);
|
||||
|
||||
boolean defaultListeners = false;
|
||||
|
||||
// Use defaults?
|
||||
if (declaringClass == null) {
|
||||
if (descriptor == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("@TestExecutionListeners is not present for class [" + clazz + "]: using defaults.");
|
||||
}
|
||||
|
|
@ -187,7 +191,11 @@ public class TestContextManager {
|
|||
}
|
||||
else {
|
||||
// Traverse the class hierarchy...
|
||||
while (declaringClass != null) {
|
||||
while (descriptor != null) {
|
||||
Class<?> rootDeclaringClass = descriptor.getDeclaringClass();
|
||||
Class<?> declaringClass = (descriptor.getStereotype() != null) ? descriptor.getStereotypeType()
|
||||
: rootDeclaringClass;
|
||||
|
||||
TestExecutionListeners testExecutionListeners = declaringClass.getAnnotation(annotationType);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Retrieved @TestExecutionListeners [" + testExecutionListeners
|
||||
|
|
@ -212,8 +220,9 @@ public class TestContextManager {
|
|||
if (listenerClasses != null) {
|
||||
classesList.addAll(0, Arrays.<Class<? extends TestExecutionListener>> asList(listenerClasses));
|
||||
}
|
||||
declaringClass = (testExecutionListeners.inheritListeners() ? AnnotationUtils.findAnnotationDeclaringClass(
|
||||
annotationType, declaringClass.getSuperclass()) : null);
|
||||
|
||||
descriptor = (testExecutionListeners.inheritListeners() ? findAnnotationDescriptor(
|
||||
rootDeclaringClass.getSuperclass(), annotationType) : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import org.junit.runners.BlockJUnit4ClassRunner;
|
|||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.annotation.ProfileValueUtils;
|
||||
import org.springframework.test.annotation.Repeat;
|
||||
import org.springframework.test.annotation.Timed;
|
||||
|
|
@ -410,7 +411,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
|
|||
* @return the timeout, or {@code 0} if none was specified.
|
||||
*/
|
||||
protected long getSpringTimeout(FrameworkMethod frameworkMethod) {
|
||||
Timed timedAnnotation = frameworkMethod.getAnnotation(Timed.class);
|
||||
Timed timedAnnotation = AnnotationUtils.getAnnotation(frameworkMethod.getMethod(), Timed.class);
|
||||
return (timedAnnotation != null && timedAnnotation.millis() > 0 ? timedAnnotation.millis() : 0);
|
||||
}
|
||||
|
||||
|
|
@ -449,7 +450,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
|
|||
* @see SpringRepeat
|
||||
*/
|
||||
protected Statement withPotentialRepeat(FrameworkMethod frameworkMethod, Object testInstance, Statement next) {
|
||||
Repeat repeatAnnotation = frameworkMethod.getAnnotation(Repeat.class);
|
||||
Repeat repeatAnnotation = AnnotationUtils.getAnnotation(frameworkMethod.getMethod(), Repeat.class);
|
||||
int repeat = (repeatAnnotation != null ? repeatAnnotation.value() : 1);
|
||||
return new SpringRepeat(next, frameworkMethod.getMethod(), repeat);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import java.lang.reflect.Method;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||
|
|
@ -28,6 +27,8 @@ import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
|
|||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
|
||||
/**
|
||||
* {@code TestExecutionListener} which provides support for marking the
|
||||
* {@code ApplicationContext} associated with a test as <em>dirty</em> for
|
||||
|
|
@ -82,9 +83,11 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
|
|||
|
||||
final Class<DirtiesContext> annotationType = DirtiesContext.class;
|
||||
|
||||
boolean methodDirtiesContext = testMethod.isAnnotationPresent(annotationType);
|
||||
boolean classDirtiesContext = testClass.isAnnotationPresent(annotationType);
|
||||
DirtiesContext classDirtiesContextAnnotation = testClass.getAnnotation(annotationType);
|
||||
DirtiesContext methodDirtiesContextAnnotation = findAnnotation(testMethod, annotationType);
|
||||
boolean methodDirtiesContext = methodDirtiesContextAnnotation != null;
|
||||
|
||||
DirtiesContext classDirtiesContextAnnotation = findAnnotation(testClass, annotationType);
|
||||
boolean classDirtiesContext = classDirtiesContextAnnotation != null;
|
||||
ClassMode classMode = classDirtiesContext ? classDirtiesContextAnnotation.classMode() : null;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
|
@ -93,8 +96,8 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
|
|||
+ methodDirtiesContext + "].");
|
||||
}
|
||||
|
||||
if (methodDirtiesContext || (classDirtiesContext && classMode == ClassMode.AFTER_EACH_TEST_METHOD)) {
|
||||
HierarchyMode hierarchyMode = methodDirtiesContext ? testMethod.getAnnotation(annotationType).hierarchyMode()
|
||||
if (methodDirtiesContext || (classMode == ClassMode.AFTER_EACH_TEST_METHOD)) {
|
||||
HierarchyMode hierarchyMode = methodDirtiesContext ? methodDirtiesContextAnnotation.hierarchyMode()
|
||||
: classDirtiesContextAnnotation.hierarchyMode();
|
||||
dirtyContext(testContext, hierarchyMode);
|
||||
}
|
||||
|
|
@ -117,12 +120,13 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
|
|||
|
||||
final Class<DirtiesContext> annotationType = DirtiesContext.class;
|
||||
|
||||
boolean dirtiesContext = testClass.isAnnotationPresent(annotationType);
|
||||
DirtiesContext dirtiesContextAnnotation = findAnnotation(testClass, annotationType);
|
||||
boolean dirtiesContext = dirtiesContextAnnotation != null;
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("After test class: context [" + testContext + "], dirtiesContext [" + dirtiesContext + "].");
|
||||
}
|
||||
if (dirtiesContext) {
|
||||
HierarchyMode hierarchyMode = testClass.getAnnotation(annotationType).hierarchyMode();
|
||||
HierarchyMode hierarchyMode = dirtiesContextAnnotation.hierarchyMode();
|
||||
dirtyContext(testContext, hierarchyMode);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,11 +17,12 @@
|
|||
package org.springframework.test.context.transaction;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Test annotation to indicate that the annotated {@code public void}
|
||||
|
|
@ -37,9 +38,10 @@ import java.lang.annotation.Target;
|
|||
* @author Sam Brannen
|
||||
* @since 2.5
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
* @see BeforeTransaction
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RUNTIME)
|
||||
@Target({ METHOD, ANNOTATION_TYPE })
|
||||
public @interface AfterTransaction {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,11 +17,12 @@
|
|||
package org.springframework.test.context.transaction;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Test annotation to indicate that the annotated {@code public void}
|
||||
|
|
@ -37,9 +38,10 @@ import java.lang.annotation.Target;
|
|||
* @author Sam Brannen
|
||||
* @since 2.5
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
* @see AfterTransaction
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RUNTIME)
|
||||
@Target({ METHOD, ANNOTATION_TYPE })
|
||||
public @interface BeforeTransaction {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,14 +27,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.annotation.Rollback;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
|
|
@ -51,6 +49,8 @@ import org.springframework.util.Assert;
|
|||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
|
||||
/**
|
||||
* {@code TestExecutionListener} that provides support for executing tests
|
||||
* within transactions by honoring the
|
||||
|
|
@ -97,16 +97,16 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
|
||||
private static final Log logger = LogFactory.getLog(TransactionalTestExecutionListener.class);
|
||||
|
||||
private static final String DEFAULT_TRANSACTION_MANAGER_NAME = (String) AnnotationUtils.getDefaultValue(
|
||||
private static final String DEFAULT_TRANSACTION_MANAGER_NAME = (String) getDefaultValue(
|
||||
TransactionConfiguration.class, "transactionManager");
|
||||
|
||||
private static final Boolean DEFAULT_DEFAULT_ROLLBACK = (Boolean) AnnotationUtils.getDefaultValue(
|
||||
TransactionConfiguration.class, "defaultRollback");
|
||||
private static final Boolean DEFAULT_DEFAULT_ROLLBACK = (Boolean) getDefaultValue(TransactionConfiguration.class,
|
||||
"defaultRollback");
|
||||
|
||||
protected final TransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource();
|
||||
|
||||
private final Map<Method, TransactionContext> transactionContextCache =
|
||||
new ConcurrentHashMap<Method, TransactionContext>(8);
|
||||
private final Map<Method, TransactionContext> transactionContextCache = new ConcurrentHashMap<Method, TransactionContext>(
|
||||
8);
|
||||
|
||||
private TransactionConfigurationAttributes configurationAttributes;
|
||||
|
||||
|
|
@ -153,14 +153,14 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
+ testContext);
|
||||
}
|
||||
|
||||
if (transactionAttribute.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
|
||||
return;
|
||||
}
|
||||
if (transactionAttribute.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
tm = getTransactionManager(testContext, transactionAttribute.getQualifier());
|
||||
}
|
||||
tm = getTransactionManager(testContext, transactionAttribute.getQualifier());
|
||||
}
|
||||
|
||||
if (tm != null) {
|
||||
if (tm != null) {
|
||||
TransactionContext txContext = new TransactionContext(tm, transactionAttribute);
|
||||
runBeforeTransactionMethods(testContext);
|
||||
startNewTransaction(testContext, txContext);
|
||||
|
|
@ -309,7 +309,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
* @throws BeansException if an error occurs while retrieving the transaction manager
|
||||
* @see #getTransactionManager(TestContext)
|
||||
*/
|
||||
protected final PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) {
|
||||
protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) {
|
||||
// look up by type and qualifier from @Transactional
|
||||
if (StringUtils.hasText(qualifier)) {
|
||||
try {
|
||||
|
|
@ -319,7 +319,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
||||
|
||||
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(bf, PlatformTransactionManager.class, qualifier);
|
||||
} catch (RuntimeException ex) {
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Caught exception while retrieving transaction manager for test context " + testContext
|
||||
+ " and qualifier [" + qualifier + "]", ex);
|
||||
|
|
@ -341,7 +342,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
* @throws BeansException if an error occurs while retrieving the transaction manager
|
||||
* @see #getTransactionManager(TestContext, String)
|
||||
*/
|
||||
protected final PlatformTransactionManager getTransactionManager(TestContext testContext) {
|
||||
protected PlatformTransactionManager getTransactionManager(TestContext testContext) {
|
||||
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
||||
String tmName = retrieveConfigurationAttributes(testContext).getTransactionManagerName();
|
||||
|
||||
|
|
@ -355,8 +356,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
ListableBeanFactory lbf = (ListableBeanFactory) bf;
|
||||
|
||||
// look up single bean by type
|
||||
Map<String, PlatformTransactionManager> txMgrs = BeanFactoryUtils.beansOfTypeIncludingAncestors(
|
||||
lbf, PlatformTransactionManager.class);
|
||||
Map<String, PlatformTransactionManager> txMgrs = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf,
|
||||
PlatformTransactionManager.class);
|
||||
if (txMgrs.size() == 1) {
|
||||
return txMgrs.values().iterator().next();
|
||||
}
|
||||
|
|
@ -376,7 +377,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
// look up by type and default name from @TransactionConfiguration
|
||||
return bf.getBean(DEFAULT_TRANSACTION_MANAGER_NAME, PlatformTransactionManager.class);
|
||||
|
||||
} catch (BeansException ex) {
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Caught exception while retrieving transaction manager for test context " + testContext, ex);
|
||||
}
|
||||
|
|
@ -408,7 +410,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
*/
|
||||
protected final boolean isRollback(TestContext testContext) throws Exception {
|
||||
boolean rollback = isDefaultRollback(testContext);
|
||||
Rollback rollbackAnnotation = testContext.getTestMethod().getAnnotation(Rollback.class);
|
||||
Rollback rollbackAnnotation = findAnnotation(testContext.getTestMethod(), Rollback.class);
|
||||
if (rollbackAnnotation != null) {
|
||||
boolean rollbackOverride = rollbackAnnotation.value();
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
|
@ -429,17 +431,17 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
/**
|
||||
* Gets all superclasses of the supplied {@link Class class}, including the
|
||||
* class itself. The ordering of the returned list will begin with the
|
||||
* supplied class and continue up the class hierarchy.
|
||||
* supplied class and continue up the class hierarchy, excluding {@link Object}.
|
||||
* <p>Note: This code has been borrowed from
|
||||
* {@link org.junit.internal.runners.TestClass#getSuperClasses(Class)} and
|
||||
* adapted.
|
||||
* @param clazz the class for which to retrieve the superclasses.
|
||||
* @return all superclasses of the supplied class.
|
||||
* @param clazz the class for which to retrieve the superclasses
|
||||
* @return all superclasses of the supplied class, excluding {@code Object}
|
||||
*/
|
||||
private List<Class<?>> getSuperClasses(Class<?> clazz) {
|
||||
ArrayList<Class<?>> results = new ArrayList<Class<?>>();
|
||||
List<Class<?>> results = new ArrayList<Class<?>>();
|
||||
Class<?> current = clazz;
|
||||
while (current != null) {
|
||||
while (current != null && !current.equals(Object.class)) {
|
||||
results.add(current);
|
||||
current = current.getSuperclass();
|
||||
}
|
||||
|
|
@ -459,12 +461,11 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
*/
|
||||
private List<Method> getAnnotatedMethods(Class<?> clazz, Class<? extends Annotation> annotationType) {
|
||||
List<Method> results = new ArrayList<Method>();
|
||||
for (Class<?> eachClass : getSuperClasses(clazz)) {
|
||||
Method[] methods = eachClass.getDeclaredMethods();
|
||||
for (Method eachMethod : methods) {
|
||||
Annotation annotation = eachMethod.getAnnotation(annotationType);
|
||||
if (annotation != null && !isShadowed(eachMethod, results)) {
|
||||
results.add(eachMethod);
|
||||
for (Class<?> current : getSuperClasses(clazz)) {
|
||||
for (Method method : current.getDeclaredMethods()) {
|
||||
Annotation annotation = getAnnotation(method, annotationType);
|
||||
if (annotation != null && !isShadowed(method, results)) {
|
||||
results.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -472,8 +473,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
}
|
||||
|
||||
/**
|
||||
* Determines if the supplied {@link Method method} is <em>shadowed</em>
|
||||
* by a method in supplied {@link List list} of previous methods.
|
||||
* Determine if the supplied {@link Method method} is <em>shadowed</em> by
|
||||
* a method in the supplied {@link List list} of previous methods.
|
||||
* <p>Note: This code has been borrowed from
|
||||
* {@link org.junit.internal.runners.TestClass#isShadowed(Method, List)}.
|
||||
* @param method the method to check for shadowing
|
||||
|
|
@ -491,8 +492,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
}
|
||||
|
||||
/**
|
||||
* Determines if the supplied {@link Method current method} is
|
||||
* <em>shadowed</em> by a {@link Method previous method}.
|
||||
* Determine if the supplied {@link Method current method} is <em>shadowed</em>
|
||||
* by a {@link Method previous method}.
|
||||
* <p>Note: This code has been borrowed from
|
||||
* {@link org.junit.internal.runners.TestClass#isShadowed(Method, Method)}.
|
||||
* @param current the current method
|
||||
|
|
@ -528,7 +529,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
private TransactionConfigurationAttributes retrieveConfigurationAttributes(TestContext testContext) {
|
||||
if (this.configurationAttributes == null) {
|
||||
Class<?> clazz = testContext.getTestClass();
|
||||
TransactionConfiguration config = clazz.getAnnotation(TransactionConfiguration.class);
|
||||
TransactionConfiguration config = findAnnotation(clazz, TransactionConfiguration.class);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved @TransactionConfiguration [" + config + "] for test class [" + clazz + "]");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.test.context.transaction;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.SimpleTransactionStatus;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TransactionalTestExecutionListener}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
public class TransactionalTestExecutionListenerTests {
|
||||
|
||||
private final PlatformTransactionManager tm = mock(PlatformTransactionManager.class);
|
||||
|
||||
private final TransactionalTestExecutionListener listener = new TransactionalTestExecutionListener() {
|
||||
|
||||
protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) {
|
||||
return tm;
|
||||
}
|
||||
};
|
||||
|
||||
private final TestContext testContext = mock(TestContext.class);
|
||||
|
||||
|
||||
private void assertBeforeTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||
assertBeforeTestMethodWithTransactionalTestMethod(clazz);
|
||||
assertBeforeTestMethodWithNonTransactionalTestMethod(clazz);
|
||||
}
|
||||
|
||||
private void assertBeforeTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
Invocable instance = clazz.newInstance();
|
||||
when(testContext.getTestInstance()).thenReturn(instance);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("transactionalTest"));
|
||||
|
||||
assertFalse(instance.invoked);
|
||||
listener.beforeTestMethod(testContext);
|
||||
assertTrue(instance.invoked);
|
||||
}
|
||||
|
||||
private void assertBeforeTestMethodWithNonTransactionalTestMethod(Class<? extends Invocable> clazz)
|
||||
throws Exception {
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
Invocable instance = clazz.newInstance();
|
||||
when(testContext.getTestInstance()).thenReturn(instance);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("nonTransactionalTest"));
|
||||
|
||||
assertFalse(instance.invoked);
|
||||
listener.beforeTestMethod(testContext);
|
||||
assertFalse(instance.invoked);
|
||||
}
|
||||
|
||||
private void assertAfterTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||
assertAfterTestMethodWithTransactionalTestMethod(clazz);
|
||||
assertAfterTestMethodWithNonTransactionalTestMethod(clazz);
|
||||
}
|
||||
|
||||
private void assertAfterTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
Invocable instance = clazz.newInstance();
|
||||
when(testContext.getTestInstance()).thenReturn(instance);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("transactionalTest"));
|
||||
|
||||
when(tm.getTransaction(Mockito.any(TransactionDefinition.class))).thenReturn(new SimpleTransactionStatus());
|
||||
|
||||
assertFalse(instance.invoked);
|
||||
listener.beforeTestMethod(testContext);
|
||||
listener.afterTestMethod(testContext);
|
||||
assertTrue(instance.invoked);
|
||||
}
|
||||
|
||||
private void assertAfterTestMethodWithNonTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
Invocable instance = clazz.newInstance();
|
||||
when(testContext.getTestInstance()).thenReturn(instance);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("nonTransactionalTest"));
|
||||
|
||||
assertFalse(instance.invoked);
|
||||
listener.beforeTestMethod(testContext);
|
||||
listener.afterTestMethod(testContext);
|
||||
assertFalse(instance.invoked);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithTransactionalDeclaredOnClassLocally() throws Exception {
|
||||
assertBeforeTestMethodWithTransactionalTestMethod(TransactionalDeclaredOnClassLocallyTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithTransactionalDeclaredOnClassViaMetaAnnotation() throws Exception {
|
||||
assertBeforeTestMethodWithTransactionalTestMethod(TransactionalDeclaredOnClassViaMetaAnnotationTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithTransactionalDeclaredOnMethodLocally() throws Exception {
|
||||
assertBeforeTestMethod(TransactionalDeclaredOnMethodLocallyTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithTransactionalDeclaredOnMethodViaMetaAnnotation() throws Exception {
|
||||
assertBeforeTestMethod(TransactionalDeclaredOnMethodViaMetaAnnotationTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithBeforeTransactionDeclaredLocally() throws Exception {
|
||||
assertBeforeTestMethod(BeforeTransactionDeclaredLocallyTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithBeforeTransactionDeclaredViaMetaAnnotation() throws Exception {
|
||||
assertBeforeTestMethod(BeforeTransactionDeclaredViaMetaAnnotationTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestMethodWithAfterTransactionDeclaredLocally() throws Exception {
|
||||
assertAfterTestMethod(AfterTransactionDeclaredLocallyTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestMethodWithAfterTransactionDeclaredViaMetaAnnotation() throws Exception {
|
||||
assertAfterTestMethod(AfterTransactionDeclaredViaMetaAnnotationTestCase.class);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Transactional
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaTransactional {
|
||||
}
|
||||
|
||||
@BeforeTransaction
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaBeforeTransaction {
|
||||
}
|
||||
|
||||
@AfterTransaction
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaAfterTransaction {
|
||||
}
|
||||
|
||||
private static abstract class Invocable {
|
||||
|
||||
boolean invoked = false;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
static class TransactionalDeclaredOnClassLocallyTestCase extends Invocable {
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
static class TransactionalDeclaredOnMethodLocallyTestCase extends Invocable {
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void nonTransactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
@MetaTransactional
|
||||
static class TransactionalDeclaredOnClassViaMetaAnnotationTestCase extends Invocable {
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void nonTransactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
static class TransactionalDeclaredOnMethodViaMetaAnnotationTestCase extends Invocable {
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
@MetaTransactional
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void nonTransactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
static class BeforeTransactionDeclaredLocallyTestCase extends Invocable {
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void nonTransactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
static class BeforeTransactionDeclaredViaMetaAnnotationTestCase extends Invocable {
|
||||
|
||||
@MetaBeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void nonTransactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
static class AfterTransactionDeclaredLocallyTestCase extends Invocable {
|
||||
|
||||
@AfterTransaction
|
||||
public void afterTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void nonTransactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
static class AfterTransactionDeclaredViaMetaAnnotationTestCase extends Invocable {
|
||||
|
||||
@MetaAfterTransaction
|
||||
public void afterTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void nonTransactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -16,14 +16,15 @@
|
|||
|
||||
package org.springframework.test.annotation;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ProfileValueUtils}.
|
||||
*
|
||||
|
|
@ -88,8 +89,12 @@ public class ProfileValueUtilsTests {
|
|||
assertClassIsEnabled(NonAnnotated.class);
|
||||
assertClassIsEnabled(EnabledAnnotatedSingleValue.class);
|
||||
assertClassIsEnabled(EnabledAnnotatedMultiValue.class);
|
||||
assertClassIsEnabled(MetaEnabledClass.class);
|
||||
assertClassIsEnabled(MetaEnabledWithCustomProfileValueSourceClass.class);
|
||||
assertClassIsDisabled(DisabledAnnotatedSingleValue.class);
|
||||
assertClassIsDisabled(DisabledAnnotatedMultiValue.class);
|
||||
assertClassIsDisabled(MetaDisabledClass.class);
|
||||
assertClassIsDisabled(MetaDisabledWithCustomProfileValueSourceClass.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -100,6 +105,10 @@ public class ProfileValueUtilsTests {
|
|||
assertMethodIsEnabled(ENABLED_ANNOTATED_METHOD, EnabledAnnotatedSingleValue.class);
|
||||
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, EnabledAnnotatedSingleValue.class);
|
||||
|
||||
assertMethodIsEnabled(NON_ANNOTATED_METHOD, MetaEnabledAnnotatedSingleValue.class);
|
||||
assertMethodIsEnabled(ENABLED_ANNOTATED_METHOD, MetaEnabledAnnotatedSingleValue.class);
|
||||
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, MetaEnabledAnnotatedSingleValue.class);
|
||||
|
||||
assertMethodIsEnabled(NON_ANNOTATED_METHOD, EnabledAnnotatedMultiValue.class);
|
||||
assertMethodIsEnabled(ENABLED_ANNOTATED_METHOD, EnabledAnnotatedMultiValue.class);
|
||||
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, EnabledAnnotatedMultiValue.class);
|
||||
|
|
@ -108,6 +117,10 @@ public class ProfileValueUtilsTests {
|
|||
assertMethodIsDisabled(ENABLED_ANNOTATED_METHOD, DisabledAnnotatedSingleValue.class);
|
||||
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, DisabledAnnotatedSingleValue.class);
|
||||
|
||||
assertMethodIsDisabled(NON_ANNOTATED_METHOD, MetaDisabledAnnotatedSingleValue.class);
|
||||
assertMethodIsDisabled(ENABLED_ANNOTATED_METHOD, MetaDisabledAnnotatedSingleValue.class);
|
||||
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, MetaDisabledAnnotatedSingleValue.class);
|
||||
|
||||
assertMethodIsDisabled(NON_ANNOTATED_METHOD, DisabledAnnotatedMultiValue.class);
|
||||
assertMethodIsDisabled(ENABLED_ANNOTATED_METHOD, DisabledAnnotatedMultiValue.class);
|
||||
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, DisabledAnnotatedMultiValue.class);
|
||||
|
|
@ -211,4 +224,82 @@ public class ProfileValueUtilsTests {
|
|||
}
|
||||
}
|
||||
|
||||
@IfProfileValue(name = NAME, value = VALUE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaEnabled {
|
||||
}
|
||||
|
||||
@IfProfileValue(name = NAME, value = VALUE + "X")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaDisabled {
|
||||
}
|
||||
|
||||
@MetaEnabled
|
||||
private static class MetaEnabledClass {
|
||||
}
|
||||
|
||||
@MetaDisabled
|
||||
private static class MetaDisabledClass {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@MetaEnabled
|
||||
private static class MetaEnabledAnnotatedSingleValue {
|
||||
|
||||
public void nonAnnotatedMethod() {
|
||||
}
|
||||
|
||||
@MetaEnabled
|
||||
public void enabledAnnotatedMethod() {
|
||||
}
|
||||
|
||||
@MetaDisabled
|
||||
public void disabledAnnotatedMethod() {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@MetaDisabled
|
||||
private static class MetaDisabledAnnotatedSingleValue {
|
||||
|
||||
public void nonAnnotatedMethod() {
|
||||
}
|
||||
|
||||
@MetaEnabled
|
||||
public void enabledAnnotatedMethod() {
|
||||
}
|
||||
|
||||
@MetaDisabled
|
||||
public void disabledAnnotatedMethod() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class HardCodedProfileValueSource implements ProfileValueSource {
|
||||
|
||||
@Override
|
||||
public String get(final String key) {
|
||||
return (key.equals(NAME) ? "42" : null);
|
||||
}
|
||||
}
|
||||
|
||||
@ProfileValueSourceConfiguration(HardCodedProfileValueSource.class)
|
||||
@IfProfileValue(name = NAME, value = "42")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaEnabledWithCustomProfileValueSource {
|
||||
}
|
||||
|
||||
@ProfileValueSourceConfiguration(HardCodedProfileValueSource.class)
|
||||
@IfProfileValue(name = NAME, value = "13")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaDisabledWithCustomProfileValueSource {
|
||||
}
|
||||
|
||||
@MetaEnabledWithCustomProfileValueSource
|
||||
private static class MetaEnabledWithCustomProfileValueSourceClass {
|
||||
}
|
||||
|
||||
@MetaDisabledWithCustomProfileValueSource
|
||||
private static class MetaDisabledWithCustomProfileValueSourceClass {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
package org.springframework.test.context;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -40,6 +44,16 @@ abstract class AbstractContextLoaderUtilsTests {
|
|||
Collections.<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> emptySet();
|
||||
|
||||
|
||||
void assertAttributes(ContextConfigurationAttributes attributes, Class<?> expectedDeclaringClass,
|
||||
String[] expectedLocations, Class<?>[] expectedClasses,
|
||||
Class<? extends ContextLoader> expectedContextLoaderClass, boolean expectedInheritLocations) {
|
||||
assertEquals(expectedDeclaringClass, attributes.getDeclaringClass());
|
||||
assertArrayEquals(expectedLocations, attributes.getLocations());
|
||||
assertArrayEquals(expectedClasses, attributes.getClasses());
|
||||
assertEquals(expectedInheritLocations, attributes.isInheritLocations());
|
||||
assertEquals(expectedContextLoaderClass, attributes.getContextLoaderClass());
|
||||
}
|
||||
|
||||
void assertMergedConfig(MergedContextConfiguration mergedConfig, Class<?> expectedTestClass,
|
||||
String[] expectedLocations, Class<?>[] expectedClasses,
|
||||
Class<? extends ContextLoader> expectedContextLoaderClass) {
|
||||
|
|
@ -61,7 +75,13 @@ abstract class AbstractContextLoaderUtilsTests {
|
|||
assertNotNull(mergedConfig.getClasses());
|
||||
assertArrayEquals(expectedClasses, mergedConfig.getClasses());
|
||||
assertNotNull(mergedConfig.getActiveProfiles());
|
||||
assertEquals(expectedContextLoaderClass, mergedConfig.getContextLoader().getClass());
|
||||
System.err.println(expectedContextLoaderClass);
|
||||
if (expectedContextLoaderClass == null) {
|
||||
assertNull(mergedConfig.getContextLoader());
|
||||
}
|
||||
else {
|
||||
assertEquals(expectedContextLoaderClass, mergedConfig.getContextLoader().getClass());
|
||||
}
|
||||
assertNotNull(mergedConfig.getContextInitializerClasses());
|
||||
assertEquals(expectedInitializerClasses, mergedConfig.getContextInitializerClasses());
|
||||
}
|
||||
|
|
@ -83,6 +103,28 @@ abstract class AbstractContextLoaderUtilsTests {
|
|||
static class BarConfig {
|
||||
}
|
||||
|
||||
@ContextConfiguration("/foo.xml")
|
||||
@ActiveProfiles(profiles = "foo")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public static @interface MetaLocationsFooConfig {
|
||||
}
|
||||
|
||||
@ContextConfiguration("/bar.xml")
|
||||
@ActiveProfiles(profiles = "bar")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public static @interface MetaLocationsBarConfig {
|
||||
}
|
||||
|
||||
@MetaLocationsFooConfig
|
||||
static class MetaLocationsFoo {
|
||||
}
|
||||
|
||||
@MetaLocationsBarConfig
|
||||
static class MetaLocationsBar extends MetaLocationsFoo {
|
||||
}
|
||||
|
||||
@ContextConfiguration(locations = "/foo.xml", inheritLocations = false)
|
||||
@ActiveProfiles(profiles = "foo")
|
||||
static class LocationsFoo {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
package org.springframework.test.context;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -107,6 +111,44 @@ public class ContextLoaderUtilsActiveProfilesTests extends AbstractContextLoader
|
|||
assertTrue(list.contains("cat"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0
|
||||
*/
|
||||
@Test
|
||||
public void resolveActiveProfilesWithMetaAnnotation() {
|
||||
String[] profiles = resolveActiveProfiles(MetaLocationsFoo.class);
|
||||
assertNotNull(profiles);
|
||||
assertArrayEquals(new String[] { "foo" }, profiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0
|
||||
*/
|
||||
@Test
|
||||
public void resolveActiveProfilesWithLocalAndInheritedMetaAnnotations() {
|
||||
String[] profiles = resolveActiveProfiles(MetaLocationsBar.class);
|
||||
assertNotNull(profiles);
|
||||
assertEquals(2, profiles.length);
|
||||
|
||||
List<String> list = Arrays.asList(profiles);
|
||||
assertTrue(list.contains("foo"));
|
||||
assertTrue(list.contains("bar"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0
|
||||
*/
|
||||
@Test
|
||||
public void resolveActiveProfilesWithOverriddenMetaAnnotation() {
|
||||
String[] profiles = resolveActiveProfiles(MetaAnimals.class);
|
||||
assertNotNull(profiles);
|
||||
assertEquals(2, profiles.length);
|
||||
|
||||
List<String> list = Arrays.asList(profiles);
|
||||
assertTrue(list.contains("dog"));
|
||||
assertTrue(list.contains("cat"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0
|
||||
*/
|
||||
|
|
@ -208,6 +250,16 @@ public class ContextLoaderUtilsActiveProfilesTests extends AbstractContextLoader
|
|||
private static class Animals extends LocationsBar {
|
||||
}
|
||||
|
||||
@ActiveProfiles(profiles = { "dog", "cat" }, inheritProfiles = false)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
private static @interface MetaAnimalsConfig {
|
||||
}
|
||||
|
||||
@MetaAnimalsConfig
|
||||
private static class MetaAnimals extends MetaLocationsBar {
|
||||
}
|
||||
|
||||
private static class InheritedLocationsFoo extends LocationsFoo {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,16 +32,6 @@ import static org.springframework.test.context.ContextLoaderUtils.*;
|
|||
*/
|
||||
public class ContextLoaderUtilsConfigurationAttributesTests extends AbstractContextLoaderUtilsTests {
|
||||
|
||||
private void assertAttributes(ContextConfigurationAttributes attributes, Class<?> expectedDeclaringClass,
|
||||
String[] expectedLocations, Class<?>[] expectedClasses,
|
||||
Class<? extends ContextLoader> expectedContextLoaderClass, boolean expectedInheritLocations) {
|
||||
assertEquals(expectedDeclaringClass, attributes.getDeclaringClass());
|
||||
assertArrayEquals(expectedLocations, attributes.getLocations());
|
||||
assertArrayEquals(expectedClasses, attributes.getClasses());
|
||||
assertEquals(expectedInheritLocations, attributes.isInheritLocations());
|
||||
assertEquals(expectedContextLoaderClass, attributes.getContextLoaderClass());
|
||||
}
|
||||
|
||||
private void assertLocationsFooAttributes(ContextConfigurationAttributes attributes) {
|
||||
assertAttributes(attributes, LocationsFoo.class, new String[] { "/foo.xml" }, EMPTY_CLASS_ARRAY,
|
||||
ContextLoader.class, false);
|
||||
|
|
@ -84,6 +74,26 @@ public class ContextLoaderUtilsConfigurationAttributesTests extends AbstractCont
|
|||
assertLocationsFooAttributes(attributesList.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConfigAttributesWithMetaAnnotationAndLocations() {
|
||||
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsFoo.class);
|
||||
assertNotNull(attributesList);
|
||||
assertEquals(1, attributesList.size());
|
||||
assertAttributes(attributesList.get(0), MetaLocationsFooConfig.class, new String[] { "/foo.xml" },
|
||||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConfigAttributesWithMetaAnnotationAndLocationsInClassHierarchy() {
|
||||
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsBar.class);
|
||||
assertNotNull(attributesList);
|
||||
assertEquals(2, attributesList.size());
|
||||
assertAttributes(attributesList.get(0), MetaLocationsBarConfig.class, new String[] { "/bar.xml" },
|
||||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
assertAttributes(attributesList.get(1), MetaLocationsFooConfig.class, new String[] { "/foo.xml" },
|
||||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConfigAttributesWithLocalAnnotationAndClasses() {
|
||||
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(ClassesFoo.class);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.test.context;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -33,7 +35,7 @@ import static org.springframework.test.context.ContextLoaderUtils.*;
|
|||
* Unit tests for {@link ContextLoaderUtils} involving context hierarchies.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoaderUtilsTests {
|
||||
|
||||
|
|
@ -48,6 +50,11 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
resolveContextHierarchyAttributes(SingleTestClassWithContextConfigurationAndContextHierarchy.class);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void resolveContextHierarchyAttributesForSingleTestClassWithContextConfigurationAndContextHierarchyOnSingleMetaAnnotation() {
|
||||
resolveContextHierarchyAttributes(SingleTestClassWithContextConfigurationAndContextHierarchyOnSingleMetaAnnotation.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForSingleTestClassWithImplicitSingleLevelContextHierarchy() {
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(BareAnnotations.class);
|
||||
|
|
@ -67,12 +74,34 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForSingleTestClassWithTripleLevelContextHierarchy() {
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(SingleTestClassWithTripleLevelContextHierarchy.class);
|
||||
public void resolveContextHierarchyAttributesForSingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation() {
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(SingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation.class);
|
||||
assertEquals(1, hierarchyAttributes.size());
|
||||
|
||||
List<ContextConfigurationAttributes> configAttributesList = hierarchyAttributes.get(0);
|
||||
assertNotNull(configAttributesList);
|
||||
assertEquals(1, configAttributesList.size());
|
||||
debugConfigAttributes(configAttributesList);
|
||||
assertAttributes(configAttributesList.get(0), ContextHierarchyA.class, new String[] { "A.xml" },
|
||||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForSingleTestClassWithTripleLevelContextHierarchy() {
|
||||
Class<SingleTestClassWithTripleLevelContextHierarchy> testClass = SingleTestClassWithTripleLevelContextHierarchy.class;
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(testClass);
|
||||
assertEquals(1, hierarchyAttributes.size());
|
||||
|
||||
List<ContextConfigurationAttributes> configAttributesList = hierarchyAttributes.get(0);
|
||||
assertNotNull(configAttributesList);
|
||||
assertEquals(3, configAttributesList.size());
|
||||
debugConfigAttributes(configAttributesList);
|
||||
assertAttributes(configAttributesList.get(0), testClass, new String[] { "A.xml" }, EMPTY_CLASS_ARRAY,
|
||||
ContextLoader.class, true);
|
||||
assertAttributes(configAttributesList.get(1), testClass, new String[] { "B.xml" },
|
||||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
assertAttributes(configAttributesList.get(2), testClass, new String[] { "C.xml" }, EMPTY_CLASS_ARRAY,
|
||||
ContextLoader.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -97,6 +126,34 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
assertThat(configAttributesListClassLevel3.get(0).getLocations()[0], equalTo("three.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForTestClassHierarchyWithSingleLevelContextHierarchiesAndMetaAnnotations() {
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(TestClass3WithSingleLevelContextHierarchyFromMetaAnnotation.class);
|
||||
assertEquals(3, hierarchyAttributes.size());
|
||||
|
||||
List<ContextConfigurationAttributes> configAttributesListClassLevel1 = hierarchyAttributes.get(0);
|
||||
debugConfigAttributes(configAttributesListClassLevel1);
|
||||
assertEquals(1, configAttributesListClassLevel1.size());
|
||||
assertThat(configAttributesListClassLevel1.get(0).getLocations()[0], equalTo("A.xml"));
|
||||
assertAttributes(configAttributesListClassLevel1.get(0), ContextHierarchyA.class, new String[] { "A.xml" },
|
||||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
|
||||
List<ContextConfigurationAttributes> configAttributesListClassLevel2 = hierarchyAttributes.get(1);
|
||||
debugConfigAttributes(configAttributesListClassLevel2);
|
||||
assertEquals(1, configAttributesListClassLevel2.size());
|
||||
assertArrayEquals(new String[] { "B-one.xml", "B-two.xml" },
|
||||
configAttributesListClassLevel2.get(0).getLocations());
|
||||
assertAttributes(configAttributesListClassLevel2.get(0), ContextHierarchyB.class, new String[] { "B-one.xml",
|
||||
"B-two.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
|
||||
List<ContextConfigurationAttributes> configAttributesListClassLevel3 = hierarchyAttributes.get(2);
|
||||
debugConfigAttributes(configAttributesListClassLevel3);
|
||||
assertEquals(1, configAttributesListClassLevel3.size());
|
||||
assertThat(configAttributesListClassLevel3.get(0).getLocations()[0], equalTo("C.xml"));
|
||||
assertAttributes(configAttributesListClassLevel3.get(0), ContextHierarchyC.class, new String[] { "C.xml" },
|
||||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForTestClassHierarchyWithBareContextConfigurationInSubclass() {
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(TestClass2WithBareContextConfigurationInSubclass.class);
|
||||
|
|
@ -301,6 +358,16 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
private static class SingleTestClassWithContextConfigurationAndContextHierarchy {
|
||||
}
|
||||
|
||||
@ContextConfiguration("foo.xml")
|
||||
@ContextHierarchy(@ContextConfiguration("bar.xml"))
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface ContextConfigurationAndContextHierarchyOnSingleMeta {
|
||||
}
|
||||
|
||||
@ContextConfigurationAndContextHierarchyOnSingleMeta
|
||||
private static class SingleTestClassWithContextConfigurationAndContextHierarchyOnSingleMetaAnnotation {
|
||||
}
|
||||
|
||||
@ContextHierarchy(@ContextConfiguration("A.xml"))
|
||||
private static class SingleTestClassWithSingleLevelContextHierarchy {
|
||||
}
|
||||
|
|
@ -465,7 +532,41 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ContextHierarchy(@ContextConfiguration("A.xml"))
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface ContextHierarchyA {
|
||||
}
|
||||
|
||||
@ContextHierarchy(@ContextConfiguration({ "B-one.xml", "B-two.xml" }))
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface ContextHierarchyB {
|
||||
}
|
||||
|
||||
@ContextHierarchy(@ContextConfiguration("C.xml"))
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface ContextHierarchyC {
|
||||
}
|
||||
|
||||
@ContextHierarchyA
|
||||
private static class SingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation {
|
||||
}
|
||||
|
||||
@ContextHierarchyA
|
||||
private static class TestClass1WithSingleLevelContextHierarchyFromMetaAnnotation {
|
||||
}
|
||||
|
||||
@ContextHierarchyB
|
||||
private static class TestClass2WithSingleLevelContextHierarchyFromMetaAnnotation extends
|
||||
TestClass1WithSingleLevelContextHierarchyFromMetaAnnotation {
|
||||
}
|
||||
|
||||
@ContextHierarchyC
|
||||
private static class TestClass3WithSingleLevelContextHierarchyFromMetaAnnotation extends
|
||||
TestClass2WithSingleLevelContextHierarchyFromMetaAnnotation {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,12 @@ import static org.springframework.test.context.ContextLoaderUtils.*;
|
|||
*/
|
||||
public class ContextLoaderUtilsMergedConfigTests extends AbstractContextLoaderUtilsTests {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@Test
|
||||
public void buildMergedConfigWithoutAnnotation() {
|
||||
buildMergedContextConfiguration(Enigma.class, null, null);
|
||||
Class<Enigma> testClass = Enigma.class;
|
||||
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass, null, null);
|
||||
|
||||
assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -57,6 +60,15 @@ public class ContextLoaderUtilsMergedConfigTests extends AbstractContextLoaderUt
|
|||
DelegatingSmartContextLoader.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedConfigWithMetaAnnotationAndLocations() {
|
||||
Class<?> testClass = MetaLocationsFoo.class;
|
||||
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass, null, null);
|
||||
|
||||
assertMergedConfig(mergedConfig, testClass, new String[] { "classpath:/foo.xml" }, EMPTY_CLASS_ARRAY,
|
||||
DelegatingSmartContextLoader.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedConfigWithLocalAnnotationAndClasses() {
|
||||
Class<?> testClass = ClassesFoo.class;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.test.context;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.test.context.MetaAnnotationUtils.AnnotationDescriptor;
|
||||
import org.springframework.test.context.MetaAnnotationUtils.UntypedAnnotationDescriptor;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.test.context.MetaAnnotationUtils.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MetaAnnotationUtils}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
public class MetaAnnotationUtilsTests {
|
||||
|
||||
private void assertComponentOnStereotype(Class<?> startClass, Class<?> declaringClass, String name,
|
||||
Class<? extends Annotation> stereotypeType) {
|
||||
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(startClass, Component.class);
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(declaringClass, descriptor.getDeclaringClass());
|
||||
assertEquals(Component.class, descriptor.getAnnotationType());
|
||||
assertEquals(name, descriptor.getAnnotation().value());
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
assertEquals(stereotypeType, descriptor.getStereotypeType());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void assertComponentOnStereotypeForMultipleCandidateTypes(Class<?> startClass, Class<?> declaringClass,
|
||||
String name, Class<? extends Annotation> stereotypeType) {
|
||||
Class<Component> annotationType = Component.class;
|
||||
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(startClass, Service.class,
|
||||
annotationType, Order.class, Transactional.class);
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(declaringClass, descriptor.getDeclaringClass());
|
||||
assertEquals(annotationType, descriptor.getAnnotationType());
|
||||
assertEquals(name, ((Component) descriptor.getAnnotation()).value());
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
assertEquals(stereotypeType, descriptor.getStereotypeType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorWithNoAnnotationPresent() throws Exception {
|
||||
assertNull(findAnnotationDescriptor(NonAnnotatedInterface.class, Transactional.class));
|
||||
assertNull(findAnnotationDescriptor(NonAnnotatedClass.class, Transactional.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorWithInheritedAnnotationOnClass() throws Exception {
|
||||
// Note: @Transactional is inherited
|
||||
assertEquals(InheritedAnnotationClass.class,
|
||||
findAnnotationDescriptor(InheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
|
||||
assertEquals(InheritedAnnotationClass.class,
|
||||
findAnnotationDescriptor(SubInheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorWithInheritedAnnotationOnInterface() throws Exception {
|
||||
// Note: @Transactional is inherited
|
||||
assertEquals(InheritedAnnotationInterface.class,
|
||||
findAnnotationDescriptor(InheritedAnnotationInterface.class, Transactional.class).getDeclaringClass());
|
||||
assertNull(findAnnotationDescriptor(SubInheritedAnnotationInterface.class, Transactional.class));
|
||||
assertNull(findAnnotationDescriptor(SubSubInheritedAnnotationInterface.class, Transactional.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForNonInheritedAnnotationOnClass() throws Exception {
|
||||
// Note: @Order is not inherited.
|
||||
assertEquals(NonInheritedAnnotationClass.class,
|
||||
findAnnotationDescriptor(NonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
|
||||
assertEquals(NonInheritedAnnotationClass.class,
|
||||
findAnnotationDescriptor(SubNonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForNonInheritedAnnotationOnInterface() throws Exception {
|
||||
// Note: @Order is not inherited.
|
||||
assertEquals(NonInheritedAnnotationInterface.class,
|
||||
findAnnotationDescriptor(NonInheritedAnnotationInterface.class, Order.class).getDeclaringClass());
|
||||
assertNull(findAnnotationDescriptor(SubNonInheritedAnnotationInterface.class, Order.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorWithMetaComponentAnnotation() throws Exception {
|
||||
Class<HasMetaComponentAnnotation> startClass = HasMetaComponentAnnotation.class;
|
||||
assertComponentOnStereotype(startClass, startClass, "meta1", Meta1.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorWithLocalAndMetaComponentAnnotation() throws Exception {
|
||||
Class<Component> annotationType = Component.class;
|
||||
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(HasLocalAndMetaComponentAnnotation.class,
|
||||
annotationType);
|
||||
assertEquals(HasLocalAndMetaComponentAnnotation.class, descriptor.getDeclaringClass());
|
||||
assertEquals(annotationType, descriptor.getAnnotationType());
|
||||
assertNull(descriptor.getStereotype());
|
||||
assertNull(descriptor.getStereotypeType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForInterfaceWithMetaAnnotation() {
|
||||
Class<InterfaceWithMetaAnnotation> startClass = InterfaceWithMetaAnnotation.class;
|
||||
assertComponentOnStereotype(startClass, startClass, "meta1", Meta1.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForClassWithMetaAnnotatedInterface() {
|
||||
assertNull(findAnnotationDescriptor(ClassWithMetaAnnotatedInterface.class, Component.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
|
||||
Class<ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface> startClass = ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class;
|
||||
assertComponentOnStereotype(startClass, startClass, "meta2", Meta2.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForSubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
|
||||
assertComponentOnStereotype(SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class,
|
||||
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, "meta2", Meta2.class);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findAnnotationDescriptorForTypesWithNoAnnotationPresent() throws Exception {
|
||||
assertNull(findAnnotationDescriptorForTypes(NonAnnotatedInterface.class, Transactional.class, Component.class));
|
||||
assertNull(findAnnotationDescriptorForTypes(NonAnnotatedClass.class, Transactional.class, Order.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findAnnotationDescriptorForTypesWithInheritedAnnotationOnClass() throws Exception {
|
||||
// Note: @Transactional is inherited
|
||||
assertEquals(InheritedAnnotationClass.class,
|
||||
findAnnotationDescriptorForTypes(InheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
|
||||
assertEquals(
|
||||
InheritedAnnotationClass.class,
|
||||
findAnnotationDescriptorForTypes(SubInheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findAnnotationDescriptorForTypesWithInheritedAnnotationOnInterface() throws Exception {
|
||||
// Note: @Transactional is inherited
|
||||
assertEquals(
|
||||
InheritedAnnotationInterface.class,
|
||||
findAnnotationDescriptorForTypes(InheritedAnnotationInterface.class, Transactional.class).getDeclaringClass());
|
||||
assertNull(findAnnotationDescriptorForTypes(SubInheritedAnnotationInterface.class, Transactional.class));
|
||||
assertNull(findAnnotationDescriptorForTypes(SubSubInheritedAnnotationInterface.class, Transactional.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnClass() throws Exception {
|
||||
// Note: @Order is not inherited.
|
||||
assertEquals(NonInheritedAnnotationClass.class,
|
||||
findAnnotationDescriptorForTypes(NonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
|
||||
assertEquals(NonInheritedAnnotationClass.class,
|
||||
findAnnotationDescriptorForTypes(SubNonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnInterface() throws Exception {
|
||||
// Note: @Order is not inherited.
|
||||
assertEquals(NonInheritedAnnotationInterface.class,
|
||||
findAnnotationDescriptorForTypes(NonInheritedAnnotationInterface.class, Order.class).getDeclaringClass());
|
||||
assertNull(findAnnotationDescriptorForTypes(SubNonInheritedAnnotationInterface.class, Order.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findAnnotationDescriptorForTypesWithLocalAndMetaComponentAnnotation() throws Exception {
|
||||
Class<Component> annotationType = Component.class;
|
||||
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
|
||||
HasLocalAndMetaComponentAnnotation.class, Transactional.class, annotationType, Order.class);
|
||||
assertEquals(HasLocalAndMetaComponentAnnotation.class, descriptor.getDeclaringClass());
|
||||
assertEquals(annotationType, descriptor.getAnnotationType());
|
||||
assertNull(descriptor.getStereotype());
|
||||
assertNull(descriptor.getStereotypeType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForTypesWithMetaComponentAnnotation() throws Exception {
|
||||
Class<HasMetaComponentAnnotation> startClass = HasMetaComponentAnnotation.class;
|
||||
assertComponentOnStereotypeForMultipleCandidateTypes(startClass, startClass, "meta1", Meta1.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForTypesForInterfaceWithMetaAnnotation() {
|
||||
Class<InterfaceWithMetaAnnotation> startClass = InterfaceWithMetaAnnotation.class;
|
||||
assertComponentOnStereotypeForMultipleCandidateTypes(startClass, startClass, "meta1", Meta1.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findAnnotationDescriptorForTypesForClassWithMetaAnnotatedInterface() {
|
||||
assertNull(findAnnotationDescriptorForTypes(ClassWithMetaAnnotatedInterface.class, Service.class,
|
||||
Component.class, Order.class, Transactional.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForTypesForClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
|
||||
Class<ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface> startClass = ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class;
|
||||
assertComponentOnStereotypeForMultipleCandidateTypes(startClass, startClass, "meta2", Meta2.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForTypesForSubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
|
||||
assertComponentOnStereotypeForMultipleCandidateTypes(
|
||||
SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class,
|
||||
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, "meta2", Meta2.class);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Component(value = "meta1")
|
||||
@Order
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface Meta1 {
|
||||
}
|
||||
|
||||
@Component(value = "meta2")
|
||||
@Transactional
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface Meta2 {
|
||||
}
|
||||
|
||||
@Meta1
|
||||
static class HasMetaComponentAnnotation {
|
||||
}
|
||||
|
||||
@Meta1
|
||||
@Component(value = "local")
|
||||
@Meta2
|
||||
static class HasLocalAndMetaComponentAnnotation {
|
||||
}
|
||||
|
||||
@Meta1
|
||||
static interface InterfaceWithMetaAnnotation {
|
||||
}
|
||||
|
||||
static class ClassWithMetaAnnotatedInterface implements InterfaceWithMetaAnnotation {
|
||||
}
|
||||
|
||||
@Meta2
|
||||
static class ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface implements InterfaceWithMetaAnnotation {
|
||||
}
|
||||
|
||||
static class SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface extends
|
||||
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Transactional
|
||||
static interface InheritedAnnotationInterface {
|
||||
}
|
||||
|
||||
static interface SubInheritedAnnotationInterface extends InheritedAnnotationInterface {
|
||||
}
|
||||
|
||||
static interface SubSubInheritedAnnotationInterface extends SubInheritedAnnotationInterface {
|
||||
}
|
||||
|
||||
@Order
|
||||
static interface NonInheritedAnnotationInterface {
|
||||
}
|
||||
|
||||
static interface SubNonInheritedAnnotationInterface extends NonInheritedAnnotationInterface {
|
||||
}
|
||||
|
||||
static class NonAnnotatedClass {
|
||||
}
|
||||
|
||||
static interface NonAnnotatedInterface {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
static class InheritedAnnotationClass {
|
||||
}
|
||||
|
||||
static class SubInheritedAnnotationClass extends InheritedAnnotationClass {
|
||||
}
|
||||
|
||||
@Order
|
||||
static class NonInheritedAnnotationClass {
|
||||
}
|
||||
|
||||
static class SubNonInheritedAnnotationClass extends NonInheritedAnnotationClass {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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,6 +18,9 @@ package org.springframework.test.context;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
|
||||
|
|
@ -42,7 +45,7 @@ public class TestExecutionListenersTests {
|
|||
@Test
|
||||
public void verifyNumDefaultListenersRegistered() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(DefaultListenersExampleTestCase.class);
|
||||
assertEquals("Verifying the number of registered TestExecutionListeners for DefaultListenersExampleTest.", 4,
|
||||
assertEquals("Num registered TELs for DefaultListenersExampleTestCase.", 4,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
|
|
@ -50,47 +53,64 @@ public class TestExecutionListenersTests {
|
|||
public void verifyNumNonInheritedDefaultListenersRegistered() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(
|
||||
NonInheritedDefaultListenersExampleTestCase.class);
|
||||
assertEquals(
|
||||
"Verifying the number of registered TestExecutionListeners for NonInheritedDefaultListenersExampleTest.",
|
||||
1, testContextManager.getTestExecutionListeners().size());
|
||||
assertEquals("Num registered TELs for NonInheritedDefaultListenersExampleTestCase.", 1,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumInheritedDefaultListenersRegistered() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(InheritedDefaultListenersExampleTestCase.class);
|
||||
assertEquals(
|
||||
"Verifying the number of registered TestExecutionListeners for InheritedDefaultListenersExampleTest.", 1,
|
||||
assertEquals("Num registered TELs for InheritedDefaultListenersExampleTestCase.", 1,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
|
||||
testContextManager = new TestContextManager(SubInheritedDefaultListenersExampleTestCase.class);
|
||||
assertEquals(
|
||||
"Verifying the number of registered TestExecutionListeners for SubInheritedDefaultListenersExampleTest.",
|
||||
1, testContextManager.getTestExecutionListeners().size());
|
||||
assertEquals("Num registered TELs for SubInheritedDefaultListenersExampleTestCase.", 1,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
|
||||
testContextManager = new TestContextManager(SubSubInheritedDefaultListenersExampleTestCase.class);
|
||||
assertEquals(
|
||||
"Verifying the number of registered TestExecutionListeners for SubSubInheritedDefaultListenersExampleTest.",
|
||||
2, testContextManager.getTestExecutionListeners().size());
|
||||
assertEquals("Num registered TELs for SubSubInheritedDefaultListenersExampleTestCase.", 2,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumListenersRegistered() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(ExampleTestCase.class);
|
||||
assertEquals("Verifying the number of registered TestExecutionListeners for ExampleTest.", 3,
|
||||
assertEquals("Num registered TELs for ExampleTestCase.", 3,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumNonInheritedListenersRegistered() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(NonInheritedListenersExampleTestCase.class);
|
||||
assertEquals("Verifying the number of registered TestExecutionListeners for NonInheritedListenersExampleTest.",
|
||||
1, testContextManager.getTestExecutionListeners().size());
|
||||
assertEquals("Num registered TELs for NonInheritedListenersExampleTestCase.", 1,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumInheritedListenersRegistered() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(InheritedListenersExampleTestCase.class);
|
||||
assertEquals("Verifying the number of registered TestExecutionListeners for InheritedListenersExampleTest.", 4,
|
||||
assertEquals("Num registered TELs for InheritedListenersExampleTestCase.", 4,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumListenersRegisteredViaMetaAnnotation() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(MetaExampleTestCase.class);
|
||||
assertEquals("Num registered TELs for MetaExampleTestCase.", 3,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumNonInheritedListenersRegisteredViaMetaAnnotation() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(MetaNonInheritedListenersExampleTestCase.class);
|
||||
assertEquals("Num registered TELs for MetaNonInheritedListenersExampleTestCase.", 1,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumInheritedListenersRegisteredViaMetaAnnotation() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(MetaInheritedListenersExampleTestCase.class);
|
||||
assertEquals("Num registered TELs for MetaInheritedListenersExampleTestCase.", 4,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +138,7 @@ public class TestExecutionListenersTests {
|
|||
static class NonInheritedDefaultListenersExampleTestCase extends InheritedDefaultListenersExampleTestCase {
|
||||
}
|
||||
|
||||
@TestExecutionListeners( { FooTestExecutionListener.class, BarTestExecutionListener.class,
|
||||
@TestExecutionListeners({ FooTestExecutionListener.class, BarTestExecutionListener.class,
|
||||
BazTestExecutionListener.class })
|
||||
static class ExampleTestCase {
|
||||
}
|
||||
|
|
@ -135,6 +155,37 @@ public class TestExecutionListenersTests {
|
|||
static class DuplicateListenersConfigExampleTestCase {
|
||||
}
|
||||
|
||||
@TestExecutionListeners({//
|
||||
FooTestExecutionListener.class,//
|
||||
BarTestExecutionListener.class,//
|
||||
BazTestExecutionListener.class //
|
||||
})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaListeners {
|
||||
}
|
||||
|
||||
@TestExecutionListeners(QuuxTestExecutionListener.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaInheritedListeners {
|
||||
}
|
||||
|
||||
@TestExecutionListeners(listeners = QuuxTestExecutionListener.class, inheritListeners = false)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaNonInheritedListeners {
|
||||
}
|
||||
|
||||
@MetaListeners
|
||||
static class MetaExampleTestCase {
|
||||
}
|
||||
|
||||
@MetaInheritedListeners
|
||||
static class MetaInheritedListenersExampleTestCase extends MetaExampleTestCase {
|
||||
}
|
||||
|
||||
@MetaNonInheritedListeners
|
||||
static class MetaNonInheritedListenersExampleTestCase extends MetaInheritedListenersExampleTestCase {
|
||||
}
|
||||
|
||||
static class FooTestExecutionListener extends AbstractTestExecutionListener {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package org.springframework.test.context.junit4;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
|
@ -77,6 +79,7 @@ public class RepeatedSpringRunnerTests {
|
|||
{ DefaultRepeatValueRepeatedTestCase.class, 0, 1, 1, 1 },//
|
||||
{ NegativeRepeatValueRepeatedTestCase.class, 0, 1, 1, 1 },//
|
||||
{ RepeatedFiveTimesRepeatedTestCase.class, 0, 1, 1, 5 },//
|
||||
{ RepeatedFiveTimesViaMetaAnnotationRepeatedTestCase.class, 0, 1, 1, 5 },//
|
||||
{ TimedRepeatedTestCase.class, 3, 4, 4, (5 + 1 + 4 + 10) } //
|
||||
});
|
||||
}
|
||||
|
|
@ -147,6 +150,20 @@ public class RepeatedSpringRunnerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Repeat(5)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface RepeatedFiveTimes {
|
||||
}
|
||||
|
||||
public static final class RepeatedFiveTimesViaMetaAnnotationRepeatedTestCase extends AbstractRepeatedTestCase {
|
||||
|
||||
@Test
|
||||
@RepeatedFiveTimes
|
||||
public void repeatedFiveTimes() throws Exception {
|
||||
incrementInvocationCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit tests for claims raised in <a
|
||||
* href="http://jira.springframework.org/browse/SPR-6011"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ package org.springframework.test.context.junit4;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
|
@ -51,11 +54,11 @@ public class TimedSpringRunnerTests {
|
|||
notifier.addListener(listener);
|
||||
|
||||
new SpringJUnit4ClassRunner(testClass).run(notifier);
|
||||
assertEquals("Verifying number of failures for test class [" + testClass + "].", 3,
|
||||
listener.getTestFailureCount());
|
||||
assertEquals("Verifying number of tests started for test class [" + testClass + "].", 5,
|
||||
assertEquals("Verifying number of tests started for test class [" + testClass + "].", 6,
|
||||
listener.getTestStartedCount());
|
||||
assertEquals("Verifying number of tests finished for test class [" + testClass + "].", 5,
|
||||
assertEquals("Verifying number of failures for test class [" + testClass + "].", 4,
|
||||
listener.getTestFailureCount());
|
||||
assertEquals("Verifying number of tests finished for test class [" + testClass + "].", 6,
|
||||
listener.getTestFinishedCount());
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +94,13 @@ public class TimedSpringRunnerTests {
|
|||
Thread.sleep(20);
|
||||
}
|
||||
|
||||
// Should Fail due to timeout.
|
||||
@Test
|
||||
@MetaTimed
|
||||
public void springTimeoutWithSleepAndMetaAnnotation() throws Exception {
|
||||
Thread.sleep(20);
|
||||
}
|
||||
|
||||
// Should Fail due to duplicate configuration.
|
||||
@Test(timeout = 200)
|
||||
@Timed(millis = 200)
|
||||
|
|
@ -99,4 +109,9 @@ public class TimedSpringRunnerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Timed(millis = 10)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaTimed {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.test.context.support;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||
import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
|
||||
import org.springframework.test.context.TestContext;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.test.annotation.DirtiesContext.HierarchyMode.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DirtiesContextTestExecutionListener}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
public class DirtiesContextTestExecutionListenerTests {
|
||||
|
||||
private final DirtiesContextTestExecutionListener listener = new DirtiesContextTestExecutionListener();
|
||||
private final TestContext testContext = mock(TestContext.class);
|
||||
|
||||
|
||||
@Test
|
||||
public void afterTestMethodForDirtiesContextDeclaredLocallyOnMethod() throws Exception {
|
||||
Class<?> clazz = getClass();
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("dirtiesContextDeclaredLocally"));
|
||||
listener.afterTestMethod(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestMethodForDirtiesContextDeclaredOnMethodViaMetaAnnotation() throws Exception {
|
||||
Class<?> clazz = getClass();
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("dirtiesContextDeclaredViaMetaAnnotation"));
|
||||
listener.afterTestMethod(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
|
||||
Class<?> clazz = DirtiesContextDeclaredLocallyAfterEachTestMethod.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("clean"));
|
||||
listener.afterTestMethod(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod() throws Exception {
|
||||
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("clean"));
|
||||
listener.afterTestMethod(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
|
||||
Class<?> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("clean"));
|
||||
listener.afterTestMethod(testContext);
|
||||
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
|
||||
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("clean"));
|
||||
listener.afterTestMethod(testContext);
|
||||
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
public void afterTestClassForDirtiesContextDeclaredLocallyOnMethod() throws Exception {
|
||||
Class<?> clazz = getClass();
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestClassForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
|
||||
Class<?> clazz = DirtiesContextDeclaredLocallyAfterEachTestMethod.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod() throws Exception {
|
||||
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestClassForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
|
||||
Class<?> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(any(HierarchyMode.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
|
||||
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(any(HierarchyMode.class));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@DirtiesContext
|
||||
void dirtiesContextDeclaredLocally() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
@MetaDirty
|
||||
void dirtiesContextDeclaredViaMetaAnnotation() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
|
||||
@DirtiesContext
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaDirty {
|
||||
}
|
||||
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaDirtyAfterEachTestMethod {
|
||||
}
|
||||
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaDirtyAfterClass {
|
||||
}
|
||||
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
static class DirtiesContextDeclaredLocallyAfterEachTestMethod {
|
||||
|
||||
void clean() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
@MetaDirtyAfterEachTestMethod
|
||||
static class DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod {
|
||||
|
||||
void clean() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
|
||||
static class DirtiesContextDeclaredLocallyAfterClass {
|
||||
|
||||
void clean() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
@MetaDirtyAfterClass
|
||||
static class DirtiesContextDeclaredViaMetaAnnotationAfterClass {
|
||||
|
||||
void clean() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.test.context.web;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Integration test that verifies meta-annotation support for {@link WebAppConfiguration}
|
||||
* and {@link org.springframework.test.context.ContextConfiguration ContextConfiguration}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
* @see WebTests
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebTests
|
||||
public class MetaAnnotationConfigWacTests {
|
||||
|
||||
@Autowired
|
||||
protected WebApplicationContext wac;
|
||||
|
||||
@Autowired
|
||||
protected MockServletContext mockServletContext;
|
||||
|
||||
@Autowired
|
||||
protected String foo;
|
||||
|
||||
|
||||
@Test
|
||||
public void fooEnigmaAutowired() {
|
||||
assertEquals("enigma", foo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicWacFeatures() throws Exception {
|
||||
assertNotNull("ServletContext should be set in the WAC.", wac.getServletContext());
|
||||
|
||||
assertNotNull("ServletContext should have been autowired from the WAC.", mockServletContext);
|
||||
|
||||
Object rootWac = mockServletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
|
||||
assertNotNull("Root WAC must be stored in the ServletContext as: "
|
||||
+ WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, rootWac);
|
||||
assertSame("test WAC and Root WAC in ServletContext must be the same object.", wac, rootWac);
|
||||
assertSame("ServletContext instances must be the same object.", mockServletContext, wac.getServletContext());
|
||||
|
||||
assertEquals("Getting real path for ServletContext resource.",
|
||||
new File("src/main/webapp/index.jsp").getCanonicalPath(), mockServletContext.getRealPath("index.jsp"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.test.context.web;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* Custom stereotype combining {@link WebAppConfiguration} and
|
||||
* {@link ContextConfiguration} as meta-annotations.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WebTests {
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public String foo() {
|
||||
return "enigma";
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue