Merge pull request #421 from sbrannen/SPR-11038
* SPR-11038: Support meta-annotation attr overrides in the TCF
This commit is contained in:
commit
c7c395d0d0
|
@ -20,9 +20,9 @@ import java.util.Arrays;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
@ -68,21 +68,29 @@ public class ContextConfigurationAttributes {
|
|||
* @throws IllegalStateException if both the locations and value attributes have been declared
|
||||
*/
|
||||
private static String[] resolveLocations(Class<?> declaringClass, ContextConfiguration contextConfiguration) {
|
||||
return resolveLocations(declaringClass, contextConfiguration.locations(), contextConfiguration.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve resource locations from the supplied {@code locations} and
|
||||
* {@code value} arrays, which correspond to attributes of the same names in
|
||||
* the {@link ContextConfiguration} annotation.
|
||||
*
|
||||
* @throws IllegalStateException if both the locations and value attributes have been declared
|
||||
*/
|
||||
private static String[] resolveLocations(Class<?> declaringClass, String[] locations, String[] value) {
|
||||
Assert.notNull(declaringClass, "declaringClass must not be null");
|
||||
|
||||
String[] locations = contextConfiguration.locations();
|
||||
String[] valueLocations = contextConfiguration.value();
|
||||
|
||||
if (!ObjectUtils.isEmpty(valueLocations) && !ObjectUtils.isEmpty(locations)) {
|
||||
if (!ObjectUtils.isEmpty(value) && !ObjectUtils.isEmpty(locations)) {
|
||||
String msg = String.format("Test class [%s] has been configured with @ContextConfiguration's 'value' %s "
|
||||
+ "and 'locations' %s attributes. Only one declaration of resource "
|
||||
+ "locations is permitted per @ContextConfiguration annotation.", declaringClass.getName(),
|
||||
ObjectUtils.nullSafeToString(valueLocations), ObjectUtils.nullSafeToString(locations));
|
||||
ObjectUtils.nullSafeToString(value), ObjectUtils.nullSafeToString(locations));
|
||||
logger.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
else if (!ObjectUtils.isEmpty(valueLocations)) {
|
||||
locations = valueLocations;
|
||||
else if (!ObjectUtils.isEmpty(value)) {
|
||||
locations = value;
|
||||
}
|
||||
|
||||
return locations;
|
||||
|
@ -101,6 +109,25 @@ public class ContextConfigurationAttributes {
|
|||
contextConfiguration.inheritInitializers(), contextConfiguration.name(), contextConfiguration.loader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@link ContextConfigurationAttributes} instance for the
|
||||
* supplied {@link ContextConfiguration @ContextConfiguration} annotation and
|
||||
* the {@linkplain Class test class} that declared it.
|
||||
* @param declaringClass the test class that declared {@code @ContextConfiguration}
|
||||
* @param annAttrs the annotation attributes from which to retrieve the attributes
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public ContextConfigurationAttributes(Class<?> declaringClass, AnnotationAttributes annAttrs) {
|
||||
this(
|
||||
declaringClass,
|
||||
resolveLocations(declaringClass, annAttrs.getStringArray("locations"), annAttrs.getStringArray("value")),
|
||||
annAttrs.getClassArray("classes"),
|
||||
annAttrs.getBoolean("inheritLocations"),
|
||||
(Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>[]) annAttrs.getClassArray("initializers"),
|
||||
annAttrs.getBoolean("inheritInitializers"), annAttrs.getString("name"),
|
||||
(Class<? extends ContextLoader>) annAttrs.getClass("loader"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@link ContextConfigurationAttributes} instance for the
|
||||
* {@linkplain Class test class} that declared the
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.context.MetaAnnotationUtils.AnnotationDescriptor;
|
||||
import org.springframework.test.context.MetaAnnotationUtils.UntypedAnnotationDescriptor;
|
||||
|
@ -192,9 +193,9 @@ abstract class ContextLoaderUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Convenience method for creating a {@link ContextConfigurationAttributes} instance
|
||||
* from the supplied {@link ContextConfiguration} and declaring class and then adding
|
||||
* the attributes to the supplied list.
|
||||
* Convenience method for creating a {@link ContextConfigurationAttributes}
|
||||
* instance from the supplied {@link ContextConfiguration} annotation and
|
||||
* declaring class and then adding the attributes to the supplied list.
|
||||
*/
|
||||
private static void convertContextConfigToConfigAttributesAndAddToList(ContextConfiguration contextConfiguration,
|
||||
Class<?> declaringClass, final List<ContextConfigurationAttributes> attributesList) {
|
||||
|
@ -211,6 +212,27 @@ abstract class ContextLoaderUtils {
|
|||
attributesList.add(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for creating a {@link ContextConfigurationAttributes}
|
||||
* instance from the supplied {@link AnnotationAttributes} and declaring
|
||||
* class and then adding the attributes to the supplied list.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
private static void convertAnnotationAttributesToConfigAttributesAndAddToList(AnnotationAttributes annAttrs,
|
||||
Class<?> declaringClass, final List<ContextConfigurationAttributes> attributesList) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(String.format("Retrieved @ContextConfiguration attributes [%s] for declaring class [%s].",
|
||||
annAttrs, declaringClass.getName()));
|
||||
}
|
||||
|
||||
ContextConfigurationAttributes attributes = new ContextConfigurationAttributes(declaringClass, annAttrs);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Resolved context configuration attributes: " + attributes);
|
||||
}
|
||||
attributesList.add(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the list of lists of {@linkplain ContextConfigurationAttributes context
|
||||
* configuration attributes} for the supplied {@linkplain Class test class} and its
|
||||
|
@ -243,6 +265,8 @@ abstract class ContextLoaderUtils {
|
|||
* <em>present</em> on the supplied class; or if a given class in the class hierarchy
|
||||
* declares both {@code @ContextConfiguration} and {@code @ContextHierarchy} as
|
||||
* top-level annotations.
|
||||
* @throws IllegalStateException if no class in the class hierarchy declares
|
||||
* {@code @ContextHierarchy}.
|
||||
*
|
||||
* @since 3.2.2
|
||||
* @see #buildContextHierarchyMap(Class)
|
||||
|
@ -251,6 +275,7 @@ abstract class ContextLoaderUtils {
|
|||
@SuppressWarnings("unchecked")
|
||||
static List<List<ContextConfigurationAttributes>> resolveContextHierarchyAttributes(Class<?> testClass) {
|
||||
Assert.notNull(testClass, "Class must not be null");
|
||||
Assert.state(findAnnotation(testClass, ContextHierarchy.class) != null, "@ContextHierarchy must be present");
|
||||
|
||||
final Class<ContextConfiguration> contextConfigType = ContextConfiguration.class;
|
||||
final Class<ContextHierarchy> contextHierarchyType = ContextHierarchy.class;
|
||||
|
@ -263,17 +288,16 @@ abstract class ContextLoaderUtils {
|
|||
contextConfigType.getName(), contextHierarchyType.getName(), testClass.getName()));
|
||||
|
||||
while (descriptor != null) {
|
||||
Class<?> rootDeclaringClass = descriptor.getDeclaringClass();
|
||||
Class<?> declaringClass = (descriptor.getStereotype() != null) ? descriptor.getStereotypeType()
|
||||
: rootDeclaringClass;
|
||||
Class<?> rootDeclaringClass = descriptor.getRootDeclaringClass();
|
||||
Class<?> declaringClass = descriptor.getDeclaringClass();
|
||||
|
||||
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 "
|
||||
String msg = String.format("Class [%s] has been configured with both @ContextConfiguration "
|
||||
+ "and @ContextHierarchy. Only one of these annotations may be declared on a test class "
|
||||
+ "or custom stereotype annotation.", rootDeclaringClass.getName());
|
||||
+ "or custom stereotype annotation.", declaringClass.getName());
|
||||
logger.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
|
@ -281,9 +305,8 @@ abstract class ContextLoaderUtils {
|
|||
final List<ContextConfigurationAttributes> configAttributesList = new ArrayList<ContextConfigurationAttributes>();
|
||||
|
||||
if (contextConfigDeclaredLocally) {
|
||||
ContextConfiguration contextConfiguration = getAnnotation(declaringClass, contextConfigType);
|
||||
convertContextConfigToConfigAttributesAndAddToList(contextConfiguration, declaringClass,
|
||||
configAttributesList);
|
||||
convertAnnotationAttributesToConfigAttributesAndAddToList(descriptor.getAnnotationAttributes(),
|
||||
declaringClass, configAttributesList);
|
||||
}
|
||||
else if (contextHierarchyDeclaredLocally) {
|
||||
ContextHierarchy contextHierarchy = getAnnotation(declaringClass, contextHierarchyType);
|
||||
|
@ -293,7 +316,7 @@ abstract class ContextLoaderUtils {
|
|||
}
|
||||
}
|
||||
else {
|
||||
// This should theoretically actually never happen...
|
||||
// This should theoretically never happen...
|
||||
String msg = String.format("Test class [%s] has been configured with neither @ContextConfiguration "
|
||||
+ "nor @ContextHierarchy as a class-level annotation.", rootDeclaringClass.getName());
|
||||
logger.error(msg);
|
||||
|
@ -405,13 +428,9 @@ abstract class ContextLoaderUtils {
|
|||
annotationType.getName(), testClass.getName()));
|
||||
|
||||
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);
|
||||
convertAnnotationAttributesToConfigAttributesAndAddToList(descriptor.getAnnotationAttributes(),
|
||||
descriptor.getDeclaringClass(), attributesList);
|
||||
descriptor = findAnnotationDescriptor(descriptor.getRootDeclaringClass().getSuperclass(), annotationType);
|
||||
}
|
||||
|
||||
return attributesList;
|
||||
|
@ -489,20 +508,18 @@ abstract class ContextLoaderUtils {
|
|||
final Set<String> activeProfiles = new HashSet<String>();
|
||||
|
||||
while (descriptor != null) {
|
||||
Class<?> rootDeclaringClass = descriptor.getDeclaringClass();
|
||||
Class<?> declaringClass = (descriptor.getStereotype() != null) ? descriptor.getStereotypeType()
|
||||
: rootDeclaringClass;
|
||||
Class<?> declaringClass = descriptor.getDeclaringClass();
|
||||
|
||||
ActiveProfiles annotation = descriptor.getAnnotation();
|
||||
AnnotationAttributes annAttrs = descriptor.getAnnotationAttributes();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(String.format("Retrieved @ActiveProfiles [%s] for declaring class [%s].", annotation,
|
||||
declaringClass.getName()));
|
||||
logger.trace(String.format("Retrieved @ActiveProfiles attributes [%s] for declaring class [%s].",
|
||||
annAttrs, declaringClass.getName()));
|
||||
}
|
||||
validateActiveProfilesConfiguration(declaringClass, annotation);
|
||||
validateActiveProfilesConfiguration(declaringClass, annAttrs);
|
||||
|
||||
String[] profiles = annotation.profiles();
|
||||
String[] valueProfiles = annotation.value();
|
||||
Class<? extends ActiveProfilesResolver> resolverClass = annotation.resolver();
|
||||
String[] profiles = annAttrs.getStringArray("profiles");
|
||||
String[] valueProfiles = annAttrs.getStringArray("value");
|
||||
Class<? extends ActiveProfilesResolver> resolverClass = annAttrs.getClass("resolver");
|
||||
|
||||
boolean resolverDeclared = !ActiveProfilesResolver.class.equals(resolverClass);
|
||||
boolean valueDeclared = !ObjectUtils.isEmpty(valueProfiles);
|
||||
|
@ -538,17 +555,17 @@ abstract class ContextLoaderUtils {
|
|||
}
|
||||
}
|
||||
|
||||
descriptor = annotation.inheritProfiles() ? findAnnotationDescriptor(rootDeclaringClass.getSuperclass(),
|
||||
annotationType) : null;
|
||||
descriptor = annAttrs.getBoolean("inheritProfiles") ? findAnnotationDescriptor(
|
||||
descriptor.getRootDeclaringClass().getSuperclass(), annotationType) : null;
|
||||
}
|
||||
|
||||
return StringUtils.toStringArray(activeProfiles);
|
||||
}
|
||||
|
||||
private static void validateActiveProfilesConfiguration(Class<?> declaringClass, ActiveProfiles annotation) {
|
||||
String[] valueProfiles = annotation.value();
|
||||
String[] profiles = annotation.profiles();
|
||||
Class<? extends ActiveProfilesResolver> resolverClass = annotation.resolver();
|
||||
private static void validateActiveProfilesConfiguration(Class<?> declaringClass, AnnotationAttributes annAttrs) {
|
||||
String[] valueProfiles = annAttrs.getStringArray("value");
|
||||
String[] profiles = annAttrs.getStringArray("profiles");
|
||||
Class<? extends ActiveProfilesResolver> resolverClass = annAttrs.getClass("resolver");
|
||||
boolean valueDeclared = !ObjectUtils.isEmpty(valueProfiles);
|
||||
boolean profilesDeclared = !ObjectUtils.isEmpty(profiles);
|
||||
boolean resolverDeclared = !ActiveProfilesResolver.class.equals(resolverClass);
|
||||
|
|
|
@ -18,6 +18,8 @@ package org.springframework.test.context;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
@ -124,7 +126,7 @@ abstract class MetaAnnotationUtils {
|
|||
* <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
|
||||
* present. In such cases, the <em>root declaring class</em> is not directly
|
||||
* annotated with the annotation but rather indirectly via the stereotype.
|
||||
*
|
||||
* <p>
|
||||
|
@ -133,6 +135,7 @@ abstract class MetaAnnotationUtils {
|
|||
* properties of the {@code AnnotationDescriptor} would be as follows.
|
||||
*
|
||||
* <ul>
|
||||
* <li>rootDeclaringClass: {@code TransactionalTests} class object</li>
|
||||
* <li>declaringClass: {@code TransactionalTests} class object</li>
|
||||
* <li>stereotype: {@code null}</li>
|
||||
* <li>annotation: instance of the {@code Transactional} annotation</li>
|
||||
|
@ -150,7 +153,8 @@ abstract class MetaAnnotationUtils {
|
|||
* properties of the {@code AnnotationDescriptor} would be as follows.
|
||||
*
|
||||
* <ul>
|
||||
* <li>declaringClass: {@code UserRepositoryTests} class object</li>
|
||||
* <li>rootDeclaringClass: {@code UserRepositoryTests} class object</li>
|
||||
* <li>declaringClass: {@code RepositoryTests} class object</li>
|
||||
* <li>stereotype: instance of the {@code RepositoryTests} annotation</li>
|
||||
* <li>annotation: instance of the {@code Transactional} annotation</li>
|
||||
* </ul>
|
||||
|
@ -170,22 +174,31 @@ abstract class MetaAnnotationUtils {
|
|||
*/
|
||||
public static class AnnotationDescriptor<T extends Annotation> {
|
||||
|
||||
private final Class<?> rootDeclaringClass;
|
||||
private final Class<?> declaringClass;
|
||||
private final Annotation stereotype;
|
||||
private final T annotation;
|
||||
private final AnnotationAttributes annotationAttributes;
|
||||
|
||||
|
||||
public AnnotationDescriptor(Class<?> declaringClass, T annotation) {
|
||||
this(declaringClass, null, annotation);
|
||||
public AnnotationDescriptor(Class<?> rootDeclaringClass, T annotation) {
|
||||
this(rootDeclaringClass, null, annotation);
|
||||
}
|
||||
|
||||
public AnnotationDescriptor(Class<?> declaringClass, Annotation stereotype, T annotation) {
|
||||
Assert.notNull(declaringClass, "declaringClass must not be null");
|
||||
public AnnotationDescriptor(Class<?> rootDeclaringClass, Annotation stereotype, T annotation) {
|
||||
Assert.notNull(rootDeclaringClass, "rootDeclaringClass must not be null");
|
||||
Assert.notNull(annotation, "annotation must not be null");
|
||||
|
||||
this.declaringClass = declaringClass;
|
||||
this.rootDeclaringClass = rootDeclaringClass;
|
||||
this.declaringClass = (stereotype != null) ? stereotype.annotationType() : rootDeclaringClass;
|
||||
this.stereotype = stereotype;
|
||||
this.annotation = annotation;
|
||||
this.annotationAttributes = AnnotatedElementUtils.getAnnotationAttributes(rootDeclaringClass,
|
||||
annotation.annotationType().getName());
|
||||
}
|
||||
|
||||
public Class<?> getRootDeclaringClass() {
|
||||
return this.rootDeclaringClass;
|
||||
}
|
||||
|
||||
public Class<?> getDeclaringClass() {
|
||||
|
@ -200,6 +213,10 @@ abstract class MetaAnnotationUtils {
|
|||
return this.annotation.annotationType();
|
||||
}
|
||||
|
||||
public AnnotationAttributes getAnnotationAttributes() {
|
||||
return this.annotationAttributes;
|
||||
}
|
||||
|
||||
public Annotation getStereotype() {
|
||||
return this.stereotype;
|
||||
}
|
||||
|
@ -214,6 +231,7 @@ abstract class MetaAnnotationUtils {
|
|||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this)//
|
||||
.append("rootDeclaringClass", rootDeclaringClass)//
|
||||
.append("declaringClass", declaringClass)//
|
||||
.append("stereotype", stereotype)//
|
||||
.append("annotation", annotation)//
|
||||
|
|
|
@ -28,6 +28,7 @@ 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.AnnotationAttributes;
|
||||
import org.springframework.test.context.MetaAnnotationUtils.AnnotationDescriptor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
@ -172,13 +173,13 @@ public class TestContextManager {
|
|||
* @param clazz the test class for which the listeners should be retrieved
|
||||
* @return an array of TestExecutionListeners for the specified class
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private TestExecutionListener[] retrieveTestExecutionListeners(Class<?> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
Class<TestExecutionListeners> annotationType = TestExecutionListeners.class;
|
||||
List<Class<? extends TestExecutionListener>> classesList = new ArrayList<Class<? extends TestExecutionListener>>();
|
||||
|
||||
AnnotationDescriptor<TestExecutionListeners> descriptor = findAnnotationDescriptor(clazz, annotationType);
|
||||
|
||||
boolean defaultListeners = false;
|
||||
|
||||
// Use defaults?
|
||||
|
@ -192,21 +193,20 @@ public class TestContextManager {
|
|||
else {
|
||||
// Traverse the class hierarchy...
|
||||
while (descriptor != null) {
|
||||
Class<?> rootDeclaringClass = descriptor.getDeclaringClass();
|
||||
Class<?> declaringClass = (descriptor.getStereotype() != null) ? descriptor.getStereotypeType()
|
||||
: rootDeclaringClass;
|
||||
Class<?> declaringClass = descriptor.getDeclaringClass();
|
||||
|
||||
TestExecutionListeners testExecutionListeners = declaringClass.getAnnotation(annotationType);
|
||||
AnnotationAttributes annAttrs = descriptor.getAnnotationAttributes();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Retrieved @TestExecutionListeners [" + testExecutionListeners
|
||||
+ "] for declaring class [" + declaringClass + "].");
|
||||
logger.trace(String.format(
|
||||
"Retrieved @TestExecutionListeners attributes [%s] for declaring class [%s].", annAttrs,
|
||||
declaringClass));
|
||||
}
|
||||
|
||||
Class<? extends TestExecutionListener>[] valueListenerClasses = testExecutionListeners.value();
|
||||
Class<? extends TestExecutionListener>[] listenerClasses = testExecutionListeners.listeners();
|
||||
Class<? extends TestExecutionListener>[] valueListenerClasses = (Class<? extends TestExecutionListener>[]) annAttrs.getClassArray("value");
|
||||
Class<? extends TestExecutionListener>[] listenerClasses = (Class<? extends TestExecutionListener>[]) annAttrs.getClassArray("listeners");
|
||||
if (!ObjectUtils.isEmpty(valueListenerClasses) && !ObjectUtils.isEmpty(listenerClasses)) {
|
||||
String msg = String.format(
|
||||
"Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] "
|
||||
"Class [%s] has been configured with @TestExecutionListeners' 'value' [%s] "
|
||||
+ "and 'listeners' [%s] attributes. Use one or the other, but not both.",
|
||||
declaringClass, ObjectUtils.nullSafeToString(valueListenerClasses),
|
||||
ObjectUtils.nullSafeToString(listenerClasses));
|
||||
|
@ -221,8 +221,8 @@ public class TestContextManager {
|
|||
classesList.addAll(0, Arrays.<Class<? extends TestExecutionListener>> asList(listenerClasses));
|
||||
}
|
||||
|
||||
descriptor = (testExecutionListeners.inheritListeners() ? findAnnotationDescriptor(
|
||||
rootDeclaringClass.getSuperclass(), annotationType) : null);
|
||||
descriptor = (annAttrs.getBoolean("inheritListeners") ? findAnnotationDescriptor(
|
||||
descriptor.getRootDeclaringClass().getSuperclass(), annotationType) : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ 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.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.annotation.ProfileValueUtils;
|
||||
import org.springframework.test.annotation.Repeat;
|
||||
|
@ -411,8 +413,15 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
|
|||
* @return the timeout, or {@code 0} if none was specified.
|
||||
*/
|
||||
protected long getSpringTimeout(FrameworkMethod frameworkMethod) {
|
||||
Timed timedAnnotation = AnnotationUtils.getAnnotation(frameworkMethod.getMethod(), Timed.class);
|
||||
return (timedAnnotation != null && timedAnnotation.millis() > 0 ? timedAnnotation.millis() : 0);
|
||||
AnnotationAttributes annAttrs = AnnotatedElementUtils.getAnnotationAttributes(frameworkMethod.getMethod(),
|
||||
Timed.class.getName());
|
||||
if (annAttrs == null) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
long millis = annAttrs.<Long> getNumber("millis").longValue();
|
||||
return millis > 0 ? millis : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,13 +21,15 @@ 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.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
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 org.springframework.util.Assert;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
import static org.springframework.test.annotation.DirtiesContext.ClassMode.*;
|
||||
|
||||
/**
|
||||
* {@code TestExecutionListener} which provides support for marking the
|
||||
|
@ -81,24 +83,22 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
|
|||
Method testMethod = testContext.getTestMethod();
|
||||
Assert.notNull(testMethod, "The test method of the supplied TestContext must not be null");
|
||||
|
||||
final Class<DirtiesContext> annotationType = DirtiesContext.class;
|
||||
|
||||
DirtiesContext methodDirtiesContextAnnotation = findAnnotation(testMethod, annotationType);
|
||||
boolean methodDirtiesContext = methodDirtiesContextAnnotation != null;
|
||||
|
||||
DirtiesContext classDirtiesContextAnnotation = findAnnotation(testClass, annotationType);
|
||||
boolean classDirtiesContext = classDirtiesContextAnnotation != null;
|
||||
ClassMode classMode = classDirtiesContext ? classDirtiesContextAnnotation.classMode() : null;
|
||||
final String annotationType = DirtiesContext.class.getName();
|
||||
AnnotationAttributes methodAnnAttrs = AnnotatedElementUtils.getAnnotationAttributes(testMethod, annotationType);
|
||||
AnnotationAttributes classAnnAttrs = AnnotatedElementUtils.getAnnotationAttributes(testClass, annotationType);
|
||||
boolean methodDirtiesContext = methodAnnAttrs != null;
|
||||
boolean classDirtiesContext = classAnnAttrs != null;
|
||||
ClassMode classMode = classDirtiesContext ? classAnnAttrs.<ClassMode> getEnum("classMode") : null;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("After test method: context [" + testContext + "], class dirties context ["
|
||||
+ classDirtiesContext + "], class mode [" + classMode + "], method dirties context ["
|
||||
+ methodDirtiesContext + "].");
|
||||
logger.debug(String.format(
|
||||
"After test method: context %s, class dirties context [%s], class mode [%s], method dirties context [%s].",
|
||||
testContext, classDirtiesContext, classMode, methodDirtiesContext));
|
||||
}
|
||||
|
||||
if (methodDirtiesContext || (classMode == ClassMode.AFTER_EACH_TEST_METHOD)) {
|
||||
HierarchyMode hierarchyMode = methodDirtiesContext ? methodDirtiesContextAnnotation.hierarchyMode()
|
||||
: classDirtiesContextAnnotation.hierarchyMode();
|
||||
if (methodDirtiesContext || (classMode == AFTER_EACH_TEST_METHOD)) {
|
||||
HierarchyMode hierarchyMode = methodDirtiesContext ? methodAnnAttrs.<HierarchyMode> getEnum("hierarchyMode")
|
||||
: classAnnAttrs.<HierarchyMode> getEnum("hierarchyMode");
|
||||
dirtyContext(testContext, hierarchyMode);
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
|
|||
* If the test class of the supplied {@linkplain TestContext test context} is
|
||||
* annotated with {@link DirtiesContext @DirtiesContext}, the
|
||||
* {@linkplain ApplicationContext application context} of the test context will
|
||||
* be {@linkplain TestContext#markApplicationContextDirty() marked as dirty} ,
|
||||
* be {@linkplain TestContext#markApplicationContextDirty() marked as dirty},
|
||||
* and the
|
||||
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
|
||||
* REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context will be set to
|
||||
|
@ -118,15 +118,16 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
|
|||
Class<?> testClass = testContext.getTestClass();
|
||||
Assert.notNull(testClass, "The test class of the supplied TestContext must not be null");
|
||||
|
||||
final Class<DirtiesContext> annotationType = DirtiesContext.class;
|
||||
final String annotationType = DirtiesContext.class.getName();
|
||||
AnnotationAttributes annAttrs = AnnotatedElementUtils.getAnnotationAttributes(testClass, annotationType);
|
||||
boolean dirtiesContext = annAttrs != null;
|
||||
|
||||
DirtiesContext dirtiesContextAnnotation = findAnnotation(testClass, annotationType);
|
||||
boolean dirtiesContext = dirtiesContextAnnotation != null;
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("After test class: context [" + testContext + "], dirtiesContext [" + dirtiesContext + "].");
|
||||
logger.debug(String.format("After test class: context %s, dirtiesContext [%s].", testContext,
|
||||
dirtiesContext));
|
||||
}
|
||||
if (dirtiesContext) {
|
||||
HierarchyMode hierarchyMode = dirtiesContextAnnotation.hierarchyMode();
|
||||
HierarchyMode hierarchyMode = annAttrs.<HierarchyMode> getEnum("hierarchyMode");
|
||||
dirtyContext(testContext, hierarchyMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ 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.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.test.annotation.Rollback;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
|
@ -414,15 +416,17 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
if (rollbackAnnotation != null) {
|
||||
boolean rollbackOverride = rollbackAnnotation.value();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method-level @Rollback(" + rollbackOverride + ") overrides default rollback [" + rollback
|
||||
+ "] for test context " + testContext);
|
||||
logger.debug(String.format(
|
||||
"Method-level @Rollback(%s) overrides default rollback [%s] for test context %s.",
|
||||
rollbackOverride, rollback, testContext));
|
||||
}
|
||||
rollback = rollbackOverride;
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No method-level @Rollback override: using default rollback [" + rollback
|
||||
+ "] for test context " + testContext);
|
||||
logger.debug(String.format(
|
||||
"No method-level @Rollback override: using default rollback [%s] for test context %s.", rollback,
|
||||
testContext));
|
||||
}
|
||||
}
|
||||
return rollback;
|
||||
|
@ -524,21 +528,25 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
* {@code @TransactionConfiguration} will be used instead.
|
||||
* @param testContext the test context for which the configuration
|
||||
* attributes should be retrieved
|
||||
* @return a new TransactionConfigurationAttributes instance
|
||||
* @return the TransactionConfigurationAttributes instance for this listener,
|
||||
* potentially cached
|
||||
*/
|
||||
private TransactionConfigurationAttributes retrieveConfigurationAttributes(TestContext testContext) {
|
||||
TransactionConfigurationAttributes retrieveConfigurationAttributes(TestContext testContext) {
|
||||
if (this.configurationAttributes == null) {
|
||||
Class<?> clazz = testContext.getTestClass();
|
||||
TransactionConfiguration config = findAnnotation(clazz, TransactionConfiguration.class);
|
||||
|
||||
AnnotationAttributes annAttrs = AnnotatedElementUtils.getAnnotationAttributes(clazz,
|
||||
TransactionConfiguration.class.getName());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved @TransactionConfiguration [" + config + "] for test class [" + clazz + "]");
|
||||
logger.debug(String.format("Retrieved @TransactionConfiguration attributes [%s] for test class [%s].",
|
||||
annAttrs, clazz));
|
||||
}
|
||||
|
||||
String transactionManagerName;
|
||||
boolean defaultRollback;
|
||||
if (config != null) {
|
||||
transactionManagerName = config.transactionManager();
|
||||
defaultRollback = config.defaultRollback();
|
||||
if (annAttrs != null) {
|
||||
transactionManagerName = annAttrs.getString("transactionManager");
|
||||
defaultRollback = annAttrs.getBoolean("defaultRollback");
|
||||
}
|
||||
else {
|
||||
transactionManagerName = DEFAULT_TRANSACTION_MANAGER_NAME;
|
||||
|
@ -548,8 +556,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||
TransactionConfigurationAttributes configAttributes = new TransactionConfigurationAttributes(
|
||||
transactionManagerName, defaultRollback);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved TransactionConfigurationAttributes " + configAttributes + " for class ["
|
||||
+ clazz + "]");
|
||||
logger.debug(String.format("Retrieved TransactionConfigurationAttributes %s for class [%s].",
|
||||
configAttributes, clazz));
|
||||
}
|
||||
this.configurationAttributes = configAttributes;
|
||||
}
|
||||
|
|
|
@ -110,6 +110,17 @@ abstract class AbstractContextLoaderUtilsTests {
|
|||
public static @interface MetaLocationsFooConfig {
|
||||
}
|
||||
|
||||
@ContextConfiguration
|
||||
@ActiveProfiles
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public static @interface MetaLocationsFooConfigWithOverrides {
|
||||
|
||||
String[] locations() default "/foo.xml";
|
||||
|
||||
String[] profiles() default "foo";
|
||||
}
|
||||
|
||||
@ContextConfiguration("/bar.xml")
|
||||
@ActiveProfiles(profiles = "bar")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
@ -125,6 +136,14 @@ abstract class AbstractContextLoaderUtilsTests {
|
|||
static class MetaLocationsBar extends MetaLocationsFoo {
|
||||
}
|
||||
|
||||
@MetaLocationsFooConfigWithOverrides
|
||||
static class MetaLocationsFooWithOverrides {
|
||||
}
|
||||
|
||||
@MetaLocationsFooConfigWithOverrides(locations = { "foo1.xml", "foo2.xml" }, profiles = { "foo1", "foo2" })
|
||||
static class MetaLocationsFooWithOverriddenAttributes {
|
||||
}
|
||||
|
||||
@ContextConfiguration(locations = "/foo.xml", inheritLocations = false)
|
||||
@ActiveProfiles(profiles = "foo")
|
||||
static class LocationsFoo {
|
||||
|
|
|
@ -121,6 +121,26 @@ public class ContextLoaderUtilsActiveProfilesTests extends AbstractContextLoader
|
|||
assertArrayEquals(new String[] { "foo" }, profiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0
|
||||
*/
|
||||
@Test
|
||||
public void resolveActiveProfilesWithMetaAnnotationAndOverrides() {
|
||||
String[] profiles = resolveActiveProfiles(MetaLocationsFooWithOverrides.class);
|
||||
assertNotNull(profiles);
|
||||
assertArrayEquals(new String[] { "foo" }, profiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0
|
||||
*/
|
||||
@Test
|
||||
public void resolveActiveProfilesWithMetaAnnotationAndOverriddenAttributes() {
|
||||
String[] profiles = resolveActiveProfiles(MetaLocationsFooWithOverriddenAttributes.class);
|
||||
assertNotNull(profiles);
|
||||
assertArrayEquals(new String[] { "foo1", "foo2" }, profiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0
|
||||
*/
|
||||
|
@ -256,6 +276,18 @@ public class ContextLoaderUtilsActiveProfilesTests extends AbstractContextLoader
|
|||
private static @interface MetaAnimalsConfig {
|
||||
}
|
||||
|
||||
@ActiveProfiles
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
private static @interface MetaProfilesWithOverrides {
|
||||
|
||||
String[] profiles() default { "dog", "cat" };
|
||||
|
||||
Class<? extends ActiveProfilesResolver> resolver() default ActiveProfilesResolver.class;
|
||||
|
||||
boolean inheritProfiles() default false;
|
||||
}
|
||||
|
||||
@MetaAnimalsConfig
|
||||
private static class MetaAnimals extends MetaLocationsBar {
|
||||
}
|
||||
|
|
|
@ -83,6 +83,24 @@ public class ContextLoaderUtilsConfigurationAttributesTests extends AbstractCont
|
|||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConfigAttributesWithMetaAnnotationAndLocationsAndOverrides() {
|
||||
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsFooWithOverrides.class);
|
||||
assertNotNull(attributesList);
|
||||
assertEquals(1, attributesList.size());
|
||||
assertAttributes(attributesList.get(0), MetaLocationsFooConfigWithOverrides.class, new String[] { "/foo.xml" },
|
||||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConfigAttributesWithMetaAnnotationAndLocationsAndOverriddenAttributes() {
|
||||
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsFooWithOverriddenAttributes.class);
|
||||
assertNotNull(attributesList);
|
||||
assertEquals(1, attributesList.size());
|
||||
assertAttributes(attributesList.get(0), MetaLocationsFooConfigWithOverrides.class, new String[] { "foo1.xml",
|
||||
"foo2.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConfigAttributesWithMetaAnnotationAndLocationsInClassHierarchy() {
|
||||
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsBar.class);
|
||||
|
|
|
@ -55,13 +55,9 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
resolveContextHierarchyAttributes(SingleTestClassWithContextConfigurationAndContextHierarchyOnSingleMetaAnnotation.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void resolveContextHierarchyAttributesForSingleTestClassWithImplicitSingleLevelContextHierarchy() {
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(BareAnnotations.class);
|
||||
assertEquals(1, hierarchyAttributes.size());
|
||||
List<ContextConfigurationAttributes> configAttributesList = hierarchyAttributes.get(0);
|
||||
assertEquals(1, configAttributesList.size());
|
||||
debugConfigAttributes(configAttributesList);
|
||||
resolveContextHierarchyAttributes(BareAnnotations.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -98,8 +94,8 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
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(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);
|
||||
}
|
||||
|
@ -154,36 +150,39 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForTestClassHierarchyWithBareContextConfigurationInSubclass() {
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(TestClass2WithBareContextConfigurationInSubclass.class);
|
||||
private void assertOneTwo(List<List<ContextConfigurationAttributes>> hierarchyAttributes) {
|
||||
assertEquals(2, hierarchyAttributes.size());
|
||||
|
||||
List<ContextConfigurationAttributes> configAttributesListClassLevel1 = hierarchyAttributes.get(0);
|
||||
List<ContextConfigurationAttributes> configAttributesListClassLevel2 = hierarchyAttributes.get(1);
|
||||
debugConfigAttributes(configAttributesListClassLevel1);
|
||||
debugConfigAttributes(configAttributesListClassLevel2);
|
||||
|
||||
assertEquals(1, configAttributesListClassLevel1.size());
|
||||
assertThat(configAttributesListClassLevel1.get(0).getLocations()[0], equalTo("one.xml"));
|
||||
|
||||
List<ContextConfigurationAttributes> configAttributesListClassLevel2 = hierarchyAttributes.get(1);
|
||||
debugConfigAttributes(configAttributesListClassLevel2);
|
||||
assertEquals(1, configAttributesListClassLevel2.size());
|
||||
assertThat(configAttributesListClassLevel2.get(0).getLocations()[0], equalTo("two.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForTestClassHierarchyWithBareContextConfigurationInSuperclass() {
|
||||
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(TestClass2WithBareContextConfigurationInSuperclass.class);
|
||||
assertEquals(2, hierarchyAttributes.size());
|
||||
assertOneTwo(resolveContextHierarchyAttributes(TestClass2WithBareContextConfigurationInSuperclass.class));
|
||||
}
|
||||
|
||||
List<ContextConfigurationAttributes> configAttributesListClassLevel1 = hierarchyAttributes.get(0);
|
||||
debugConfigAttributes(configAttributesListClassLevel1);
|
||||
assertEquals(1, configAttributesListClassLevel1.size());
|
||||
assertThat(configAttributesListClassLevel1.get(0).getLocations()[0], equalTo("one.xml"));
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForTestClassHierarchyWithBareContextConfigurationInSubclass() {
|
||||
assertOneTwo(resolveContextHierarchyAttributes(TestClass2WithBareContextConfigurationInSubclass.class));
|
||||
}
|
||||
|
||||
List<ContextConfigurationAttributes> configAttributesListClassLevel2 = hierarchyAttributes.get(1);
|
||||
debugConfigAttributes(configAttributesListClassLevel2);
|
||||
assertEquals(1, configAttributesListClassLevel2.size());
|
||||
assertThat(configAttributesListClassLevel2.get(0).getLocations()[0], equalTo("two.xml"));
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForTestClassHierarchyWithBareMetaContextConfigWithOverridesInSuperclass() {
|
||||
assertOneTwo(resolveContextHierarchyAttributes(TestClass2WithBareMetaContextConfigWithOverridesInSuperclass.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextHierarchyAttributesForTestClassHierarchyWithBareMetaContextConfigWithOverridesInSubclass() {
|
||||
assertOneTwo(resolveContextHierarchyAttributes(TestClass2WithBareMetaContextConfigWithOverridesInSubclass.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -408,7 +407,7 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
|
||||
@ContextConfiguration("two.xml")
|
||||
private static class TestClass2WithBareContextConfigurationInSubclass extends
|
||||
TestClass1WithBareContextConfigurationInSuperclass {
|
||||
TestClass1WithBareContextConfigurationInSubclass {
|
||||
}
|
||||
|
||||
@ContextHierarchy({//
|
||||
|
@ -569,4 +568,31 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
|
|||
TestClass2WithSingleLevelContextHierarchyFromMetaAnnotation {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ContextConfiguration
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface ContextConfigWithOverrides {
|
||||
|
||||
String[] locations() default "A.xml";
|
||||
}
|
||||
|
||||
@ContextConfigWithOverrides(locations = "one.xml")
|
||||
private static class TestClass1WithBareMetaContextConfigWithOverridesInSuperclass {
|
||||
}
|
||||
|
||||
@ContextHierarchy(@ContextConfiguration(locations = "two.xml"))
|
||||
private static class TestClass2WithBareMetaContextConfigWithOverridesInSuperclass extends
|
||||
TestClass1WithBareMetaContextConfigWithOverridesInSuperclass {
|
||||
}
|
||||
|
||||
@ContextHierarchy(@ContextConfiguration(locations = "one.xml"))
|
||||
private static class TestClass1WithBareMetaContextConfigWithOverridesInSubclass {
|
||||
}
|
||||
|
||||
@ContextConfigWithOverrides(locations = "two.xml")
|
||||
private static class TestClass2WithBareMetaContextConfigWithOverridesInSubclass extends
|
||||
TestClass1WithBareMetaContextConfigWithOverridesInSubclass {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public class MetaAnnotationUtilsTests {
|
|||
Class<? extends Annotation> stereotypeType) {
|
||||
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(startClass, Component.class);
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(declaringClass, descriptor.getDeclaringClass());
|
||||
assertEquals(declaringClass, descriptor.getRootDeclaringClass());
|
||||
assertEquals(Component.class, descriptor.getAnnotationType());
|
||||
assertEquals(name, descriptor.getAnnotation().value());
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
|
@ -57,7 +57,7 @@ public class MetaAnnotationUtilsTests {
|
|||
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(startClass, Service.class,
|
||||
annotationType, Order.class, Transactional.class);
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(declaringClass, descriptor.getDeclaringClass());
|
||||
assertEquals(declaringClass, descriptor.getRootDeclaringClass());
|
||||
assertEquals(annotationType, descriptor.getAnnotationType());
|
||||
assertEquals(name, ((Component) descriptor.getAnnotation()).value());
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
|
@ -74,16 +74,16 @@ public class MetaAnnotationUtilsTests {
|
|||
public void findAnnotationDescriptorWithInheritedAnnotationOnClass() throws Exception {
|
||||
// Note: @Transactional is inherited
|
||||
assertEquals(InheritedAnnotationClass.class,
|
||||
findAnnotationDescriptor(InheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
|
||||
findAnnotationDescriptor(InheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass());
|
||||
assertEquals(InheritedAnnotationClass.class,
|
||||
findAnnotationDescriptor(SubInheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
|
||||
findAnnotationDescriptor(SubInheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorWithInheritedAnnotationOnInterface() throws Exception {
|
||||
// Note: @Transactional is inherited
|
||||
assertEquals(InheritedAnnotationInterface.class,
|
||||
findAnnotationDescriptor(InheritedAnnotationInterface.class, Transactional.class).getDeclaringClass());
|
||||
findAnnotationDescriptor(InheritedAnnotationInterface.class, Transactional.class).getRootDeclaringClass());
|
||||
assertNull(findAnnotationDescriptor(SubInheritedAnnotationInterface.class, Transactional.class));
|
||||
assertNull(findAnnotationDescriptor(SubSubInheritedAnnotationInterface.class, Transactional.class));
|
||||
}
|
||||
|
@ -92,16 +92,16 @@ public class MetaAnnotationUtilsTests {
|
|||
public void findAnnotationDescriptorForNonInheritedAnnotationOnClass() throws Exception {
|
||||
// Note: @Order is not inherited.
|
||||
assertEquals(NonInheritedAnnotationClass.class,
|
||||
findAnnotationDescriptor(NonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
|
||||
findAnnotationDescriptor(NonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass());
|
||||
assertEquals(NonInheritedAnnotationClass.class,
|
||||
findAnnotationDescriptor(SubNonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
|
||||
findAnnotationDescriptor(SubNonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForNonInheritedAnnotationOnInterface() throws Exception {
|
||||
// Note: @Order is not inherited.
|
||||
assertEquals(NonInheritedAnnotationInterface.class,
|
||||
findAnnotationDescriptor(NonInheritedAnnotationInterface.class, Order.class).getDeclaringClass());
|
||||
findAnnotationDescriptor(NonInheritedAnnotationInterface.class, Order.class).getRootDeclaringClass());
|
||||
assertNull(findAnnotationDescriptor(SubNonInheritedAnnotationInterface.class, Order.class));
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ public class MetaAnnotationUtilsTests {
|
|||
Class<Component> annotationType = Component.class;
|
||||
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(HasLocalAndMetaComponentAnnotation.class,
|
||||
annotationType);
|
||||
assertEquals(HasLocalAndMetaComponentAnnotation.class, descriptor.getDeclaringClass());
|
||||
assertEquals(HasLocalAndMetaComponentAnnotation.class, descriptor.getRootDeclaringClass());
|
||||
assertEquals(annotationType, descriptor.getAnnotationType());
|
||||
assertNull(descriptor.getStereotype());
|
||||
assertNull(descriptor.getStereotypeType());
|
||||
|
@ -159,10 +159,10 @@ public class MetaAnnotationUtilsTests {
|
|||
public void findAnnotationDescriptorForTypesWithInheritedAnnotationOnClass() throws Exception {
|
||||
// Note: @Transactional is inherited
|
||||
assertEquals(InheritedAnnotationClass.class,
|
||||
findAnnotationDescriptorForTypes(InheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
|
||||
findAnnotationDescriptorForTypes(InheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass());
|
||||
assertEquals(
|
||||
InheritedAnnotationClass.class,
|
||||
findAnnotationDescriptorForTypes(SubInheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
|
||||
findAnnotationDescriptorForTypes(SubInheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -171,7 +171,7 @@ public class MetaAnnotationUtilsTests {
|
|||
// Note: @Transactional is inherited
|
||||
assertEquals(
|
||||
InheritedAnnotationInterface.class,
|
||||
findAnnotationDescriptorForTypes(InheritedAnnotationInterface.class, Transactional.class).getDeclaringClass());
|
||||
findAnnotationDescriptorForTypes(InheritedAnnotationInterface.class, Transactional.class).getRootDeclaringClass());
|
||||
assertNull(findAnnotationDescriptorForTypes(SubInheritedAnnotationInterface.class, Transactional.class));
|
||||
assertNull(findAnnotationDescriptorForTypes(SubSubInheritedAnnotationInterface.class, Transactional.class));
|
||||
}
|
||||
|
@ -181,9 +181,9 @@ public class MetaAnnotationUtilsTests {
|
|||
public void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnClass() throws Exception {
|
||||
// Note: @Order is not inherited.
|
||||
assertEquals(NonInheritedAnnotationClass.class,
|
||||
findAnnotationDescriptorForTypes(NonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
|
||||
findAnnotationDescriptorForTypes(NonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass());
|
||||
assertEquals(NonInheritedAnnotationClass.class,
|
||||
findAnnotationDescriptorForTypes(SubNonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
|
||||
findAnnotationDescriptorForTypes(SubNonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -191,7 +191,7 @@ public class MetaAnnotationUtilsTests {
|
|||
public void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnInterface() throws Exception {
|
||||
// Note: @Order is not inherited.
|
||||
assertEquals(NonInheritedAnnotationInterface.class,
|
||||
findAnnotationDescriptorForTypes(NonInheritedAnnotationInterface.class, Order.class).getDeclaringClass());
|
||||
findAnnotationDescriptorForTypes(NonInheritedAnnotationInterface.class, Order.class).getRootDeclaringClass());
|
||||
assertNull(findAnnotationDescriptorForTypes(SubNonInheritedAnnotationInterface.class, Order.class));
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ public class MetaAnnotationUtilsTests {
|
|||
Class<Component> annotationType = Component.class;
|
||||
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
|
||||
HasLocalAndMetaComponentAnnotation.class, Transactional.class, annotationType, Order.class);
|
||||
assertEquals(HasLocalAndMetaComponentAnnotation.class, descriptor.getDeclaringClass());
|
||||
assertEquals(HasLocalAndMetaComponentAnnotation.class, descriptor.getRootDeclaringClass());
|
||||
assertEquals(annotationType, descriptor.getAnnotationType());
|
||||
assertNull(descriptor.getStereotype());
|
||||
assertNull(descriptor.getStereotypeType());
|
||||
|
@ -213,6 +213,44 @@ public class MetaAnnotationUtilsTests {
|
|||
assertComponentOnStereotypeForMultipleCandidateTypes(startClass, startClass, "meta1", Meta1.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findAnnotationDescriptorForTypesWithMetaAnnotationWithDefaultAttributes() throws Exception {
|
||||
Class<?> startClass = MetaConfigWithDefaultAttributesTestCase.class;
|
||||
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
|
||||
|
||||
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(startClass, Service.class,
|
||||
ContextConfiguration.class, Order.class, Transactional.class);
|
||||
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(startClass, descriptor.getRootDeclaringClass());
|
||||
assertEquals(annotationType, descriptor.getAnnotationType());
|
||||
assertArrayEquals(new Class[] {}, ((ContextConfiguration) descriptor.getAnnotation()).value());
|
||||
assertArrayEquals(new Class[] { MetaConfig.DevConfig.class, MetaConfig.ProductionConfig.class },
|
||||
descriptor.getAnnotationAttributes().getClassArray("classes"));
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
assertEquals(MetaConfig.class, descriptor.getStereotypeType());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findAnnotationDescriptorForTypesWithMetaAnnotationWithOverriddenAttributes() throws Exception {
|
||||
Class<?> startClass = MetaConfigWithOverriddenAttributesTestCase.class;
|
||||
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
|
||||
|
||||
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(startClass, Service.class,
|
||||
ContextConfiguration.class, Order.class, Transactional.class);
|
||||
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(startClass, descriptor.getRootDeclaringClass());
|
||||
assertEquals(annotationType, descriptor.getAnnotationType());
|
||||
assertArrayEquals(new Class[] {}, ((ContextConfiguration) descriptor.getAnnotation()).value());
|
||||
assertArrayEquals(new Class[] { MetaAnnotationUtilsTests.class },
|
||||
descriptor.getAnnotationAttributes().getClassArray("classes"));
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
assertEquals(MetaConfig.class, descriptor.getStereotypeType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationDescriptorForTypesForInterfaceWithMetaAnnotation() {
|
||||
Class<InterfaceWithMetaAnnotation> startClass = InterfaceWithMetaAnnotation.class;
|
||||
|
@ -279,6 +317,28 @@ public class MetaAnnotationUtilsTests {
|
|||
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface {
|
||||
}
|
||||
|
||||
@ContextConfiguration
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaConfig {
|
||||
|
||||
static class DevConfig {
|
||||
}
|
||||
|
||||
static class ProductionConfig {
|
||||
}
|
||||
|
||||
|
||||
Class<?>[] classes() default { DevConfig.class, ProductionConfig.class };
|
||||
}
|
||||
|
||||
@MetaConfig
|
||||
public class MetaConfigWithDefaultAttributesTestCase {
|
||||
}
|
||||
|
||||
@MetaConfig(classes = MetaAnnotationUtilsTests.class)
|
||||
public class MetaConfigWithOverriddenAttributesTestCase {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Transactional
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.test.context.MetaAnnotationUtils.AnnotationDescriptor;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.test.context.MetaAnnotationUtils.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MetaAnnotationUtils} that verify support for overridden
|
||||
* meta-annotation attributes.
|
||||
*
|
||||
* <p>See <a href="https://jira.springsource.org/browse/SPR-10181">SPR-10181</a>.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
public class OverriddenMetaAnnotationAttributesTests {
|
||||
|
||||
@Test
|
||||
public void contextConfigurationValue() throws Exception {
|
||||
Class<MetaValueConfigTest> declaringClass = MetaValueConfigTest.class;
|
||||
AnnotationDescriptor<ContextConfiguration> descriptor = findAnnotationDescriptor(declaringClass,
|
||||
ContextConfiguration.class);
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(declaringClass, descriptor.getRootDeclaringClass());
|
||||
assertEquals(MetaValueConfig.class, descriptor.getStereotypeType());
|
||||
assertEquals(ContextConfiguration.class, descriptor.getAnnotationType());
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
assertEquals(MetaValueConfig.class, descriptor.getStereotypeType());
|
||||
|
||||
// direct access to annotation value:
|
||||
assertArrayEquals(new String[] { "foo.xml" }, descriptor.getAnnotation().value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overriddenContextConfigurationValue() throws Exception {
|
||||
Class<?> declaringClass = OverriddenMetaValueConfigTest.class;
|
||||
AnnotationDescriptor<ContextConfiguration> descriptor = findAnnotationDescriptor(declaringClass,
|
||||
ContextConfiguration.class);
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(declaringClass, descriptor.getRootDeclaringClass());
|
||||
assertEquals(MetaValueConfig.class, descriptor.getStereotypeType());
|
||||
assertEquals(ContextConfiguration.class, descriptor.getAnnotationType());
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
assertEquals(MetaValueConfig.class, descriptor.getStereotypeType());
|
||||
|
||||
// direct access to annotation value:
|
||||
assertArrayEquals(new String[] { "foo.xml" }, descriptor.getAnnotation().value());
|
||||
|
||||
// overridden attribute:
|
||||
AnnotationAttributes attributes = descriptor.getAnnotationAttributes();
|
||||
|
||||
// NOTE: we would like to be able to override the 'value' attribute; however,
|
||||
// Spring currently does not allow overrides for the 'value' attribute.
|
||||
// TODO Determine if Spring should allow overrides for the 'value' attribute in
|
||||
// custom annotations.
|
||||
assertArrayEquals(new String[] { "foo.xml" }, attributes.getStringArray("value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contextConfigurationLocationsAndInheritLocations() throws Exception {
|
||||
Class<MetaLocationsConfigTest> declaringClass = MetaLocationsConfigTest.class;
|
||||
AnnotationDescriptor<ContextConfiguration> descriptor = findAnnotationDescriptor(declaringClass,
|
||||
ContextConfiguration.class);
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(declaringClass, descriptor.getRootDeclaringClass());
|
||||
assertEquals(MetaLocationsConfig.class, descriptor.getStereotypeType());
|
||||
assertEquals(ContextConfiguration.class, descriptor.getAnnotationType());
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
assertEquals(MetaLocationsConfig.class, descriptor.getStereotypeType());
|
||||
|
||||
// direct access to annotation attributes:
|
||||
assertArrayEquals(new String[] { "foo.xml" }, descriptor.getAnnotation().locations());
|
||||
assertFalse(descriptor.getAnnotation().inheritLocations());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overriddenContextConfigurationLocationsAndInheritLocations() throws Exception {
|
||||
Class<?> declaringClass = OverriddenMetaLocationsConfigTest.class;
|
||||
AnnotationDescriptor<ContextConfiguration> descriptor = findAnnotationDescriptor(declaringClass,
|
||||
ContextConfiguration.class);
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(declaringClass, descriptor.getRootDeclaringClass());
|
||||
assertEquals(MetaLocationsConfig.class, descriptor.getStereotypeType());
|
||||
assertEquals(ContextConfiguration.class, descriptor.getAnnotationType());
|
||||
assertNotNull(descriptor.getStereotype());
|
||||
assertEquals(MetaLocationsConfig.class, descriptor.getStereotypeType());
|
||||
|
||||
// direct access to annotation attributes:
|
||||
assertArrayEquals(new String[] { "foo.xml" }, descriptor.getAnnotation().locations());
|
||||
assertFalse(descriptor.getAnnotation().inheritLocations());
|
||||
|
||||
// overridden attributes:
|
||||
AnnotationAttributes attributes = descriptor.getAnnotationAttributes();
|
||||
assertArrayEquals(new String[] { "bar.xml" }, attributes.getStringArray("locations"));
|
||||
assertTrue(attributes.getBoolean("inheritLocations"));
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ContextConfiguration("foo.xml")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaValueConfig {
|
||||
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@MetaValueConfig
|
||||
public static class MetaValueConfigTest {
|
||||
}
|
||||
|
||||
@MetaValueConfig("bar.xml")
|
||||
public static class OverriddenMetaValueConfigTest {
|
||||
}
|
||||
|
||||
@ContextConfiguration(locations = "foo.xml", inheritLocations = false)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaLocationsConfig {
|
||||
|
||||
String[] locations() default {};
|
||||
|
||||
boolean inheritLocations();
|
||||
}
|
||||
|
||||
@MetaLocationsConfig(inheritLocations = true)
|
||||
static class MetaLocationsConfigTest {
|
||||
}
|
||||
|
||||
@MetaLocationsConfig(locations = "bar.xml", inheritLocations = true)
|
||||
static class OverriddenMetaLocationsConfigTest {
|
||||
}
|
||||
|
||||
}
|
|
@ -16,14 +16,14 @@
|
|||
|
||||
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;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* JUnit 4 based unit test for the {@link TestExecutionListeners
|
||||
|
@ -114,6 +114,29 @@ public class TestExecutionListenersTests {
|
|||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumListenersRegisteredViaMetaAnnotationWithOverrides() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(MetaWithOverridesExampleTestCase.class);
|
||||
assertEquals("Num registered TELs for MetaWithOverridesExampleTestCase.", 3,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumListenersRegisteredViaMetaAnnotationWithInheritedListenersWithOverrides() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(
|
||||
MetaInheritedListenersWithOverridesExampleTestCase.class);
|
||||
assertEquals("Num registered TELs for MetaInheritedListenersWithOverridesExampleTestCase.", 5,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyNumListenersRegisteredViaMetaAnnotationWithNonInheritedListenersWithOverrides() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(
|
||||
MetaNonInheritedListenersWithOverridesExampleTestCase.class);
|
||||
assertEquals("Num registered TELs for MetaNonInheritedListenersWithOverridesExampleTestCase.", 8,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void verifyDuplicateListenersConfigThrowsException() throws Exception {
|
||||
new TestContextManager(DuplicateListenersConfigExampleTestCase.class);
|
||||
|
@ -174,6 +197,32 @@ public class TestExecutionListenersTests {
|
|||
static @interface MetaNonInheritedListeners {
|
||||
}
|
||||
|
||||
@TestExecutionListeners
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaListenersWithOverrides {
|
||||
|
||||
Class<? extends TestExecutionListener>[] listeners() default { FooTestExecutionListener.class,
|
||||
BarTestExecutionListener.class };
|
||||
}
|
||||
|
||||
@TestExecutionListeners
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaInheritedListenersWithOverrides {
|
||||
|
||||
Class<? extends TestExecutionListener>[] listeners() default QuuxTestExecutionListener.class;
|
||||
|
||||
boolean inheritListeners() default true;
|
||||
}
|
||||
|
||||
@TestExecutionListeners
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaNonInheritedListenersWithOverrides {
|
||||
|
||||
Class<? extends TestExecutionListener>[] listeners() default QuuxTestExecutionListener.class;
|
||||
|
||||
boolean inheritListeners() default false;
|
||||
}
|
||||
|
||||
@MetaListeners
|
||||
static class MetaExampleTestCase {
|
||||
}
|
||||
|
@ -186,6 +235,28 @@ public class TestExecutionListenersTests {
|
|||
static class MetaNonInheritedListenersExampleTestCase extends MetaInheritedListenersExampleTestCase {
|
||||
}
|
||||
|
||||
@MetaListenersWithOverrides(listeners = {//
|
||||
FooTestExecutionListener.class,//
|
||||
BarTestExecutionListener.class,//
|
||||
BazTestExecutionListener.class //
|
||||
})
|
||||
static class MetaWithOverridesExampleTestCase {
|
||||
}
|
||||
|
||||
@MetaInheritedListenersWithOverrides(listeners = { FooTestExecutionListener.class, BarTestExecutionListener.class })
|
||||
static class MetaInheritedListenersWithOverridesExampleTestCase extends MetaWithOverridesExampleTestCase {
|
||||
}
|
||||
|
||||
@MetaNonInheritedListenersWithOverrides(listeners = {//
|
||||
FooTestExecutionListener.class,//
|
||||
BarTestExecutionListener.class,//
|
||||
BazTestExecutionListener.class //
|
||||
},//
|
||||
inheritListeners = true)
|
||||
static class MetaNonInheritedListenersWithOverridesExampleTestCase extends
|
||||
MetaInheritedListenersWithOverridesExampleTestCase {
|
||||
}
|
||||
|
||||
static class FooTestExecutionListener extends AbstractTestExecutionListener {
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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,13 +16,21 @@
|
|||
|
||||
package org.springframework.test.context.junit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.springframework.test.annotation.Timed;
|
||||
import org.springframework.test.context.TestContextManager;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Rick Evans
|
||||
* Unit tests for {@link SpringJUnit4ClassRunner}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Rick Evans
|
||||
* @since 2.5
|
||||
*/
|
||||
public class SpringJUnit4ClassRunnerTests {
|
||||
|
@ -37,7 +45,8 @@ public class SpringJUnit4ClassRunnerTests {
|
|||
|
||||
@Override
|
||||
public void prepareTestInstance(Object testInstance) {
|
||||
throw new RuntimeException("This RuntimeException should be caught and wrapped in an Exception.");
|
||||
throw new RuntimeException(
|
||||
"This RuntimeException should be caught and wrapped in an Exception.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -45,4 +54,45 @@ public class SpringJUnit4ClassRunnerTests {
|
|||
runner.createTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSpringTimeoutViaMetaAnnotation() throws Exception {
|
||||
SpringJUnit4ClassRunner runner = new SpringJUnit4ClassRunner(getClass());
|
||||
long timeout = runner.getSpringTimeout(new FrameworkMethod(getClass().getDeclaredMethod(
|
||||
"springTimeoutWithMetaAnnotation")));
|
||||
assertEquals(10, timeout);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSpringTimeoutViaMetaAnnotationWithOverride() throws Exception {
|
||||
SpringJUnit4ClassRunner runner = new SpringJUnit4ClassRunner(getClass());
|
||||
long timeout = runner.getSpringTimeout(new FrameworkMethod(getClass().getDeclaredMethod(
|
||||
"springTimeoutWithMetaAnnotationAndOverride")));
|
||||
assertEquals(42, timeout);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@MetaTimed
|
||||
void springTimeoutWithMetaAnnotation() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
@MetaTimedWithOverride(millis = 42)
|
||||
void springTimeoutWithMetaAnnotationAndOverride() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
|
||||
@Timed(millis = 10)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaTimed {
|
||||
}
|
||||
|
||||
@Timed(millis = 1000)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaTimedWithOverride {
|
||||
|
||||
long millis() default 1000;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.test.context.junit4;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
@ -31,6 +29,8 @@ import org.springframework.test.context.TestExecutionListeners;
|
|||
import org.springframework.tests.Assume;
|
||||
import org.springframework.tests.TestGroup;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Verifies proper handling of the following in conjunction with the
|
||||
* {@link SpringJUnit4ClassRunner}:
|
||||
|
@ -54,11 +54,11 @@ public class TimedSpringRunnerTests {
|
|||
notifier.addListener(listener);
|
||||
|
||||
new SpringJUnit4ClassRunner(testClass).run(notifier);
|
||||
assertEquals("Verifying number of tests started for test class [" + testClass + "].", 6,
|
||||
assertEquals("Verifying number of tests started for test class [" + testClass + "].", 7,
|
||||
listener.getTestStartedCount());
|
||||
assertEquals("Verifying number of failures for test class [" + testClass + "].", 4,
|
||||
assertEquals("Verifying number of failures for test class [" + testClass + "].", 5,
|
||||
listener.getTestFailureCount());
|
||||
assertEquals("Verifying number of tests finished for test class [" + testClass + "].", 6,
|
||||
assertEquals("Verifying number of tests finished for test class [" + testClass + "].", 7,
|
||||
listener.getTestFinishedCount());
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,13 @@ public class TimedSpringRunnerTests {
|
|||
Thread.sleep(20);
|
||||
}
|
||||
|
||||
// Should Fail due to timeout.
|
||||
@Test
|
||||
@MetaTimedWithOverride(millis = 10)
|
||||
public void springTimeoutWithSleepAndMetaAnnotationAndOverride() throws Exception {
|
||||
Thread.sleep(20);
|
||||
}
|
||||
|
||||
// Should Fail due to duplicate configuration.
|
||||
@Test(timeout = 200)
|
||||
@Timed(millis = 200)
|
||||
|
@ -114,4 +121,11 @@ public class TimedSpringRunnerTests {
|
|||
private static @interface MetaTimed {
|
||||
}
|
||||
|
||||
@Timed(millis = 1000)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaTimedWithOverride {
|
||||
|
||||
long millis() default 1000;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.junit4.annotation.meta;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* Custom configuration annotation with meta-annotation attribute overrides for
|
||||
* {@link ContextConfiguration#classes} and {@link ActiveProfiles#profiles}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@ActiveProfiles
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface MetaConfig {
|
||||
|
||||
@Configuration
|
||||
@Profile("dev")
|
||||
static class DevConfig {
|
||||
|
||||
@Bean
|
||||
public String foo() {
|
||||
return "Dev Foo";
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Profile("prod")
|
||||
static class ProductionConfig {
|
||||
|
||||
@Bean
|
||||
public String foo() {
|
||||
return "Production Foo";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Class<?>[] classes() default { DevConfig.class, ProductionConfig.class };
|
||||
|
||||
String[] profiles() default "dev";
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.junit4.annotation.meta;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Integration tests for meta-annotation attribute override support, relying on
|
||||
* default attribute values defined in {@link MetaConfig}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@MetaConfig
|
||||
public class MetaConfigDefaultsTests {
|
||||
|
||||
@Autowired
|
||||
private String foo;
|
||||
|
||||
|
||||
@Test
|
||||
public void foo() {
|
||||
assertEquals("Dev Foo", foo);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.junit4.annotation.meta;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.junit4.annotation.PojoAndStringConfig;
|
||||
import org.springframework.tests.sample.beans.Employee;
|
||||
import org.springframework.tests.sample.beans.Pet;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Integration tests for meta-annotation attribute override support, overriding
|
||||
* default attribute values defined in {@link MetaConfig}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@MetaConfig(classes = { PojoAndStringConfig.class, MetaConfig.ProductionConfig.class }, profiles = "prod")
|
||||
public class MetaConfigOverrideTests {
|
||||
|
||||
@Autowired
|
||||
private String foo;
|
||||
|
||||
@Autowired
|
||||
private Pet pet;
|
||||
|
||||
@Autowired
|
||||
protected Employee employee;
|
||||
|
||||
|
||||
@Test
|
||||
public void verifyEmployee() {
|
||||
assertNotNull("The employee should have been autowired.", this.employee);
|
||||
assertEquals("John Smith", this.employee.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyPet() {
|
||||
assertNotNull("The pet should have been autowired.", this.pet);
|
||||
assertEquals("Fido", this.pet.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyFoo() {
|
||||
assertEquals("Production Foo", this.foo);
|
||||
}
|
||||
}
|
|
@ -26,8 +26,8 @@ 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.ClassMode.*;
|
||||
import static org.springframework.test.annotation.DirtiesContext.HierarchyMode.*;
|
||||
|
||||
/**
|
||||
|
@ -84,7 +84,7 @@ public class DirtiesContextTestExecutionListenerTests {
|
|||
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));
|
||||
verify(testContext, times(0)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -93,7 +93,16 @@ public class DirtiesContextTestExecutionListenerTests {
|
|||
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));
|
||||
verify(testContext, times(0)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestMethodForDirtiesContextViaMetaAnnotationWithOverrides() throws Exception {
|
||||
Class<?> clazz = DirtiesContextViaMetaAnnotationWithOverrides.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("clean"));
|
||||
listener.afterTestMethod(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(CURRENT_LEVEL);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -103,7 +112,7 @@ public class DirtiesContextTestExecutionListenerTests {
|
|||
Class<?> clazz = getClass();
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
|
||||
verify(testContext, times(0)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -127,7 +136,7 @@ public class DirtiesContextTestExecutionListenerTests {
|
|||
Class<?> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(any(HierarchyMode.class));
|
||||
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -135,7 +144,23 @@ public class DirtiesContextTestExecutionListenerTests {
|
|||
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(any(HierarchyMode.class));
|
||||
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationWithOverrides() throws Exception {
|
||||
Class<?> clazz = DirtiesContextViaMetaAnnotationWithOverrides.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(CURRENT_LEVEL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationWithOverridenAttributes() throws Exception {
|
||||
Class<?> clazz = DirtiesContextViaMetaAnnotationWithOverridenAttributes.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
listener.afterTestClass(testContext);
|
||||
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -156,17 +181,17 @@ public class DirtiesContextTestExecutionListenerTests {
|
|||
static @interface MetaDirty {
|
||||
}
|
||||
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaDirtyAfterEachTestMethod {
|
||||
}
|
||||
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
|
||||
@DirtiesContext(classMode = AFTER_CLASS)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaDirtyAfterClass {
|
||||
}
|
||||
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
|
||||
static class DirtiesContextDeclaredLocallyAfterEachTestMethod {
|
||||
|
||||
void clean() {
|
||||
|
@ -174,6 +199,15 @@ public class DirtiesContextTestExecutionListenerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@DirtiesContext
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaDirtyWithOverrides {
|
||||
|
||||
ClassMode classMode() default AFTER_EACH_TEST_METHOD;
|
||||
|
||||
HierarchyMode hierarchyMode() default HierarchyMode.CURRENT_LEVEL;
|
||||
}
|
||||
|
||||
@MetaDirtyAfterEachTestMethod
|
||||
static class DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod {
|
||||
|
||||
|
@ -182,7 +216,7 @@ public class DirtiesContextTestExecutionListenerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
|
||||
@DirtiesContext(classMode = AFTER_CLASS)
|
||||
static class DirtiesContextDeclaredLocallyAfterClass {
|
||||
|
||||
void clean() {
|
||||
|
@ -198,4 +232,20 @@ public class DirtiesContextTestExecutionListenerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@MetaDirtyWithOverrides
|
||||
static class DirtiesContextViaMetaAnnotationWithOverrides {
|
||||
|
||||
void clean() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
@MetaDirtyWithOverrides(classMode = AFTER_CLASS, hierarchyMode = EXHAUSTIVE)
|
||||
static class DirtiesContextViaMetaAnnotationWithOverridenAttributes {
|
||||
|
||||
void clean() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,14 +21,17 @@ import java.lang.annotation.RetentionPolicy;
|
|||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.test.annotation.Rollback;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.SimpleTransactionStatus;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.transaction.annotation.Propagation.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TransactionalTestExecutionListener}.
|
||||
|
@ -56,6 +59,11 @@ public class TransactionalTestExecutionListenerTests {
|
|||
}
|
||||
|
||||
private void assertBeforeTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||
assertBeforeTestMethodWithTransactionalTestMethod(clazz, true);
|
||||
}
|
||||
|
||||
private void assertBeforeTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz, boolean invokedInTx)
|
||||
throws Exception {
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
Invocable instance = clazz.newInstance();
|
||||
when(testContext.getTestInstance()).thenReturn(instance);
|
||||
|
@ -63,7 +71,7 @@ public class TransactionalTestExecutionListenerTests {
|
|||
|
||||
assertFalse(instance.invoked);
|
||||
listener.beforeTestMethod(testContext);
|
||||
assertTrue(instance.invoked);
|
||||
assertEquals(invokedInTx, instance.invoked);
|
||||
}
|
||||
|
||||
private void assertBeforeTestMethodWithNonTransactionalTestMethod(Class<? extends Invocable> clazz)
|
||||
|
@ -109,6 +117,22 @@ public class TransactionalTestExecutionListenerTests {
|
|||
assertFalse(instance.invoked);
|
||||
}
|
||||
|
||||
private void assertTransactionConfigurationAttributes(Class<?> clazz, String transactionManagerName,
|
||||
boolean defaultRollback) {
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
|
||||
TransactionConfigurationAttributes attributes = listener.retrieveConfigurationAttributes(testContext);
|
||||
assertNotNull(attributes);
|
||||
assertEquals(transactionManagerName, attributes.getTransactionManagerName());
|
||||
assertEquals(defaultRollback, attributes.isDefaultRollback());
|
||||
}
|
||||
|
||||
private void assertIsRollback(Class<?> clazz, boolean rollback) throws NoSuchMethodException, Exception {
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("test"));
|
||||
assertEquals(rollback, listener.isRollback(testContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithTransactionalDeclaredOnClassLocally() throws Exception {
|
||||
assertBeforeTestMethodWithTransactionalTestMethod(TransactionalDeclaredOnClassLocallyTestCase.class);
|
||||
|
@ -119,6 +143,23 @@ public class TransactionalTestExecutionListenerTests {
|
|||
assertBeforeTestMethodWithTransactionalTestMethod(TransactionalDeclaredOnClassViaMetaAnnotationTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithTransactionalDeclaredOnClassViaMetaAnnotationWithOverride() throws Exception {
|
||||
// Note: not actually invoked within a transaction since the test class is
|
||||
// annotated with @MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
||||
assertBeforeTestMethodWithTransactionalTestMethod(
|
||||
TransactionalDeclaredOnClassViaMetaAnnotationWithOverrideTestCase.class, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithTransactionalDeclaredOnMethodViaMetaAnnotationWithOverride() throws Exception {
|
||||
// Note: not actually invoked within a transaction since the method is
|
||||
// annotated with @MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
||||
assertBeforeTestMethodWithTransactionalTestMethod(
|
||||
TransactionalDeclaredOnMethodViaMetaAnnotationWithOverrideTestCase.class, false);
|
||||
assertBeforeTestMethodWithNonTransactionalTestMethod(TransactionalDeclaredOnMethodViaMetaAnnotationWithOverrideTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeTestMethodWithTransactionalDeclaredOnMethodLocally() throws Exception {
|
||||
assertBeforeTestMethod(TransactionalDeclaredOnMethodLocallyTestCase.class);
|
||||
|
@ -149,6 +190,55 @@ public class TransactionalTestExecutionListenerTests {
|
|||
assertAfterTestMethod(AfterTransactionDeclaredViaMetaAnnotationTestCase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveConfigurationAttributesWithMissingTransactionConfiguration() throws Exception {
|
||||
assertTransactionConfigurationAttributes(MissingTransactionConfigurationTestCase.class, "transactionManager",
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveConfigurationAttributesWithEmptyTransactionConfiguration() throws Exception {
|
||||
assertTransactionConfigurationAttributes(EmptyTransactionConfigurationTestCase.class, "transactionManager",
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveConfigurationAttributesWithExplicitValues() throws Exception {
|
||||
assertTransactionConfigurationAttributes(TransactionConfigurationWithExplicitValuesTestCase.class, "tm", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveConfigurationAttributesViaMetaAnnotation() throws Exception {
|
||||
assertTransactionConfigurationAttributes(TransactionConfigurationViaMetaAnnotationTestCase.class, "metaTxMgr",
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveConfigurationAttributesViaMetaAnnotationWithOverride() throws Exception {
|
||||
assertTransactionConfigurationAttributes(TransactionConfigurationViaMetaAnnotationWithOverrideTestCase.class,
|
||||
"overriddenTxMgr", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRollbackWithMissingRollback() throws Exception {
|
||||
assertIsRollback(MissingRollbackTestCase.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRollbackWithEmptyRollback() throws Exception {
|
||||
assertIsRollback(EmptyRollbackTestCase.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRollbackWithExplicitValue() throws Exception {
|
||||
assertIsRollback(RollbackWithExplicitValueTestCase.class, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRollbackViaMetaAnnotation() throws Exception {
|
||||
assertIsRollback(RollbackViaMetaAnnotationTestCase.class, false);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
|
@ -157,6 +247,13 @@ public class TransactionalTestExecutionListenerTests {
|
|||
private static @interface MetaTransactional {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaTxWithOverride {
|
||||
|
||||
Propagation propagation() default REQUIRED;
|
||||
}
|
||||
|
||||
@BeforeTransaction
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaBeforeTransaction {
|
||||
|
@ -167,6 +264,18 @@ public class TransactionalTestExecutionListenerTests {
|
|||
private static @interface MetaAfterTransaction {
|
||||
}
|
||||
|
||||
@TransactionConfiguration
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface MetaTxConfig {
|
||||
|
||||
String transactionManager() default "metaTxMgr";
|
||||
}
|
||||
|
||||
@Rollback(false)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface Commit {
|
||||
}
|
||||
|
||||
private static abstract class Invocable {
|
||||
|
||||
boolean invoked = false;
|
||||
|
@ -213,10 +322,6 @@ public class TransactionalTestExecutionListenerTests {
|
|||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void nonTransactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
static class TransactionalDeclaredOnMethodViaMetaAnnotationTestCase extends Invocable {
|
||||
|
@ -236,6 +341,36 @@ public class TransactionalTestExecutionListenerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
||||
static class TransactionalDeclaredOnClassViaMetaAnnotationWithOverrideTestCase extends Invocable {
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
static class TransactionalDeclaredOnMethodViaMetaAnnotationWithOverrideTestCase extends Invocable {
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
@MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
||||
public void transactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
public void nonTransactionalTest() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
||||
static class BeforeTransactionDeclaredLocallyTestCase extends Invocable {
|
||||
|
||||
@BeforeTransaction
|
||||
|
@ -304,4 +439,50 @@ public class TransactionalTestExecutionListenerTests {
|
|||
}
|
||||
}
|
||||
|
||||
static class MissingTransactionConfigurationTestCase {
|
||||
}
|
||||
|
||||
@TransactionConfiguration
|
||||
static class EmptyTransactionConfigurationTestCase {
|
||||
}
|
||||
|
||||
@TransactionConfiguration(transactionManager = "tm", defaultRollback = false)
|
||||
static class TransactionConfigurationWithExplicitValuesTestCase {
|
||||
}
|
||||
|
||||
@MetaTxConfig
|
||||
static class TransactionConfigurationViaMetaAnnotationTestCase {
|
||||
}
|
||||
|
||||
@MetaTxConfig(transactionManager = "overriddenTxMgr")
|
||||
static class TransactionConfigurationViaMetaAnnotationWithOverrideTestCase {
|
||||
}
|
||||
|
||||
static class MissingRollbackTestCase {
|
||||
|
||||
public void test() {
|
||||
}
|
||||
}
|
||||
|
||||
static class EmptyRollbackTestCase {
|
||||
|
||||
@Rollback
|
||||
public void test() {
|
||||
}
|
||||
}
|
||||
|
||||
static class RollbackWithExplicitValueTestCase {
|
||||
|
||||
@Rollback(false)
|
||||
public void test() {
|
||||
}
|
||||
}
|
||||
|
||||
static class RollbackViaMetaAnnotationTestCase {
|
||||
|
||||
@Commit
|
||||
public void test() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue