[SPR-5710] Subclasses of SpringJUnit4ClassRunner can now override the default ContextLoader class via the new getDefaultContextLoaderClassName(Class) method.
This commit is contained in:
@@ -24,7 +24,6 @@ import java.util.List;
|
||||
|
||||
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.AttributeAccessorSupport;
|
||||
@@ -32,11 +31,12 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* TestContext encapsulates the context in which a test is executed,
|
||||
* agnostic of the actual testing framework in use.
|
||||
*
|
||||
* TestContext encapsulates the context in which a test is executed, agnostic of
|
||||
* the actual testing framework in use.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
@@ -45,12 +45,10 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
|
||||
private static final long serialVersionUID = -5827157174866681233L;
|
||||
|
||||
private static final String DEFAULT_CONTEXT_LOADER_CLASS_NAME =
|
||||
"org.springframework.test.context.support.GenericXmlContextLoader";
|
||||
private static final String STANDARD_DEFAULT_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.GenericXmlContextLoader";
|
||||
|
||||
private static final Log logger = LogFactory.getLog(TestContext.class);
|
||||
|
||||
|
||||
private final ContextCache contextCache;
|
||||
|
||||
private final ContextLoader contextLoader;
|
||||
@@ -66,20 +64,46 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
private Throwable testException;
|
||||
|
||||
|
||||
/**
|
||||
* Delegates to {@link #TestContext(Class, ContextCache, String)} with a
|
||||
* value of <code>null</code> for the default <code>ContextLoader</code>
|
||||
* class name.
|
||||
*/
|
||||
TestContext(Class<?> testClass, ContextCache contextCache) {
|
||||
this(testClass, contextCache, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new test context for the supplied {@link Class test class}
|
||||
* and {@link ContextCache context cache} and parses the corresponding
|
||||
* {@link ContextConfiguration @ContextConfiguration} annotation, if present.
|
||||
* @param testClass the {@link Class} object corresponding to the test class
|
||||
* for which the test context should be constructed (must not be <code>null</code>)
|
||||
* @param contextCache the context cache from which the constructed test context
|
||||
* should retrieve application contexts (must not be <code>null</code>)
|
||||
* and {@link ContextCache context cache} and parse the corresponding
|
||||
* {@link ContextConfiguration @ContextConfiguration} annotation, if
|
||||
* present.
|
||||
* <p>
|
||||
* If the supplied class name for the default ContextLoader is
|
||||
* <code>null</code> or <em>empty</em> and no <code>ContextLoader</code>
|
||||
* class is explicitly supplied via the
|
||||
* <code>@ContextConfiguration</code> annotation, a
|
||||
* {@link org.springframework.test.context.support.GenericXmlContextLoader
|
||||
* GenericXmlContextLoader} will be used instead.
|
||||
* </p>
|
||||
*
|
||||
* @param testClass the test class for which the test context should be
|
||||
* constructed (must not be <code>null</code>)
|
||||
* @param contextCache the context cache from which the constructed test
|
||||
* context should retrieve application contexts (must not be
|
||||
* <code>null</code>)
|
||||
* @param defaultContextLoaderClassName the name of the default
|
||||
* <code>ContextLoader</code> class to use (may be <code>null</code>)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
TestContext(Class<?> testClass, ContextCache contextCache) {
|
||||
TestContext(Class<?> testClass, ContextCache contextCache, String defaultContextLoaderClassName) {
|
||||
Assert.notNull(testClass, "Test class must not be null");
|
||||
Assert.notNull(contextCache, "ContextCache must not be null");
|
||||
|
||||
if (!StringUtils.hasText(defaultContextLoaderClassName)) {
|
||||
defaultContextLoaderClassName = STANDARD_DEFAULT_CONTEXT_LOADER_CLASS_NAME;
|
||||
}
|
||||
|
||||
ContextConfiguration contextConfiguration = testClass.getAnnotation(ContextConfiguration.class);
|
||||
String[] locations = null;
|
||||
ContextLoader contextLoader = null;
|
||||
@@ -91,18 +115,24 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
}
|
||||
else {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Retrieved @ContextConfiguration [" + contextConfiguration + "] for class [" + testClass + "]");
|
||||
logger.trace("Retrieved @ContextConfiguration [" + contextConfiguration + "] for class [" + testClass
|
||||
+ "]");
|
||||
}
|
||||
|
||||
Class<? extends ContextLoader> contextLoaderClass = contextConfiguration.loader();
|
||||
if (ContextLoader.class.equals(contextLoaderClass)) {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Using default ContextLoader class [" + defaultContextLoaderClassName
|
||||
+ "] for @ContextConfiguration [" + contextConfiguration + "] and class [" + testClass
|
||||
+ "]");
|
||||
}
|
||||
contextLoaderClass = (Class<? extends ContextLoader>) getClass().getClassLoader().loadClass(
|
||||
DEFAULT_CONTEXT_LOADER_CLASS_NAME);
|
||||
defaultContextLoaderClassName);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException("Could not load default ContextLoader class ["
|
||||
+ DEFAULT_CONTEXT_LOADER_CLASS_NAME + "]. Specify @ContextConfiguration's 'loader' "
|
||||
+ defaultContextLoaderClassName + "]. Specify @ContextConfiguration's 'loader' "
|
||||
+ "attribute or make the default loader class available.");
|
||||
}
|
||||
}
|
||||
@@ -119,21 +149,24 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
/**
|
||||
* Retrieve {@link ApplicationContext} resource locations for the supplied
|
||||
* {@link Class class}, using the supplied {@link ContextLoader} to
|
||||
* {@link ContextLoader#processLocations(Class, String...) process} the locations.
|
||||
* <p>Note that the
|
||||
* {@link ContextConfiguration#inheritLocations() inheritLocations} flag of
|
||||
* {@link ContextConfiguration @ContextConfiguration} will be taken into
|
||||
* consideration. Specifically, if the <code>inheritLocations</code> flag
|
||||
* is set to <code>true</code>, locations defined in the annotated class
|
||||
* will be appended to the locations defined in superclasses.
|
||||
* @param contextLoader the ContextLoader to use for processing the locations
|
||||
* (must not be <code>null</code>)
|
||||
* @param clazz the class for which to retrieve the resource locations
|
||||
* (must not be <code>null</code>)
|
||||
* @return the list of ApplicationContext resource locations for the specified
|
||||
* class, including locations from superclasses if appropriate
|
||||
* @throws IllegalArgumentException if {@link ContextConfiguration @ContextConfiguration}
|
||||
* is not <em>present</em> on the supplied class
|
||||
* {@link ContextLoader#processLocations(Class, String...) process} the
|
||||
* locations.
|
||||
* <p>
|
||||
* Note that the {@link ContextConfiguration#inheritLocations()
|
||||
* inheritLocations} flag of {@link ContextConfiguration
|
||||
* @ContextConfiguration} will be taken into consideration.
|
||||
* Specifically, if the <code>inheritLocations</code> flag is set to
|
||||
* <code>true</code>, locations defined in the annotated class will be
|
||||
* appended to the locations defined in superclasses. @param
|
||||
* contextLoader the ContextLoader to use for processing the locations (must
|
||||
* not be <code>null</code>)
|
||||
*
|
||||
* @param clazz the class for which to retrieve the resource locations (must
|
||||
* not be <code>null</code>)
|
||||
* @return the list of ApplicationContext resource locations for the
|
||||
* specified class, including locations from superclasses if appropriate
|
||||
* @throws IllegalArgumentException if {@link ContextConfiguration
|
||||
* @ContextConfiguration} is not <em>present</em> on the supplied class
|
||||
*/
|
||||
private String[] retrieveContextLocations(ContextLoader contextLoader, Class<?> clazz) {
|
||||
Assert.notNull(contextLoader, "ContextLoader must not be null");
|
||||
@@ -142,8 +175,8 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
List<String> locationsList = new ArrayList<String>();
|
||||
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
|
||||
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
|
||||
Assert.notNull(declaringClass, "Could not find an 'annotation declaring class' for annotation type [" +
|
||||
annotationType + "] and class [" + clazz + "]");
|
||||
Assert.notNull(declaringClass, "Could not find an 'annotation declaring class' for annotation type ["
|
||||
+ annotationType + "] and class [" + clazz + "]");
|
||||
|
||||
while (declaringClass != null) {
|
||||
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
|
||||
@@ -154,28 +187,30 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
String[] locations = contextLoader.processLocations(declaringClass, contextConfiguration.locations());
|
||||
locationsList.addAll(0, Arrays.<String> asList(locations));
|
||||
declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass(
|
||||
annotationType, declaringClass.getSuperclass()) : null;
|
||||
annotationType, declaringClass.getSuperclass()) : null;
|
||||
}
|
||||
|
||||
return locationsList.toArray(new String[locationsList.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an ApplicationContext for this test context using the
|
||||
* configured ContextLoader and resource locations.
|
||||
* @throws Exception if an error occurs while building the application context
|
||||
* Build an ApplicationContext for this test context using the configured
|
||||
* ContextLoader and resource locations.
|
||||
*
|
||||
* @throws Exception if an error occurs while building the application
|
||||
* context
|
||||
*/
|
||||
private ApplicationContext loadApplicationContext() throws Exception {
|
||||
Assert.notNull(this.contextLoader, "Can not build an ApplicationContext with a NULL 'contextLoader'. " +
|
||||
"Consider annotating your test class with @ContextConfiguration.");
|
||||
Assert.notNull(this.locations, "Can not build an ApplicationContext with a NULL 'locations' array. " +
|
||||
"Consider annotating your test class with @ContextConfiguration.");
|
||||
Assert.notNull(this.contextLoader, "Can not build an ApplicationContext with a NULL 'contextLoader'. "
|
||||
+ "Consider annotating your test class with @ContextConfiguration.");
|
||||
Assert.notNull(this.locations, "Can not build an ApplicationContext with a NULL 'locations' array. "
|
||||
+ "Consider annotating your test class with @ContextConfiguration.");
|
||||
return this.contextLoader.loadContext(this.locations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the supplied context <code>key</code> to a String
|
||||
* representation for use in caching, logging, etc.
|
||||
* Convert the supplied context <code>key</code> to a String representation
|
||||
* for use in caching, logging, etc.
|
||||
*/
|
||||
private String contextKeyString(Serializable key) {
|
||||
return ObjectUtils.nullSafeToString(key);
|
||||
@@ -184,9 +219,11 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
/**
|
||||
* Get the {@link ApplicationContext application context} for this test
|
||||
* context, possibly cached.
|
||||
* @return the application context; may be <code>null</code> if the
|
||||
* current test context is not configured to use an application context
|
||||
* @throws IllegalStateException if an error occurs while retrieving the application context
|
||||
*
|
||||
* @return the application context; may be <code>null</code> if the current
|
||||
* test context is not configured to use an application context
|
||||
* @throws IllegalStateException if an error occurs while retrieving the
|
||||
* application context
|
||||
*/
|
||||
public ApplicationContext getApplicationContext() {
|
||||
synchronized (this.contextCache) {
|
||||
@@ -206,6 +243,7 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
|
||||
/**
|
||||
* Get the {@link Class test class} for this test context.
|
||||
*
|
||||
* @return the test class (never <code>null</code>)
|
||||
*/
|
||||
public final Class<?> getTestClass() {
|
||||
@@ -214,7 +252,9 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
|
||||
/**
|
||||
* Get the current {@link Object test instance} for this test context.
|
||||
* <p>Note: this is a mutable property.
|
||||
* <p>
|
||||
* Note: this is a mutable property.
|
||||
*
|
||||
* @return the current test instance (may be <code>null</code>)
|
||||
* @see #updateState(Object,Method,Throwable)
|
||||
*/
|
||||
@@ -224,7 +264,9 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
|
||||
/**
|
||||
* Get the current {@link Method test method} for this test context.
|
||||
* <p>Note: this is a mutable property.
|
||||
* <p>
|
||||
* Note: this is a mutable property.
|
||||
*
|
||||
* @return the current test method (may be <code>null</code>)
|
||||
* @see #updateState(Object, Method, Throwable)
|
||||
*/
|
||||
@@ -235,7 +277,9 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
/**
|
||||
* Get the {@link Throwable exception} that was thrown during execution of
|
||||
* the {@link #getTestMethod() test method}.
|
||||
* <p>Note: this is a mutable property.
|
||||
* <p>
|
||||
* Note: this is a mutable property.
|
||||
*
|
||||
* @return the exception that was thrown, or <code>null</code> if no
|
||||
* exception was thrown
|
||||
* @see #updateState(Object, Method, Throwable)
|
||||
@@ -245,21 +289,23 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to signal that the
|
||||
* {@link ApplicationContext application context} associated with this test
|
||||
* context is <em>dirty</em> and should be reloaded. Do this if a test has
|
||||
* modified the context (for example, by replacing a bean definition).
|
||||
* Call this method to signal that the {@link ApplicationContext application
|
||||
* context} associated with this test context is <em>dirty</em> and should
|
||||
* be reloaded. Do this if a test has modified the context (for example, by
|
||||
* replacing a bean definition).
|
||||
*/
|
||||
public void markApplicationContextDirty() {
|
||||
this.contextCache.setDirty(contextKeyString(this.locations));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this test context to reflect the state of the currently executing test.
|
||||
* Update this test context to reflect the state of the currently executing
|
||||
* test.
|
||||
*
|
||||
* @param testInstance the current test instance (may be <code>null</code>)
|
||||
* @param testMethod the current test method (may be <code>null</code>)
|
||||
* @param testException the exception that was thrown in the test method,
|
||||
* or <code>null</code> if no exception was thrown
|
||||
* @param testException the exception that was thrown in the test method, or
|
||||
* <code>null</code> if no exception was thrown
|
||||
*/
|
||||
void updateState(Object testInstance, Method testMethod, Throwable testException) {
|
||||
this.testInstance = testInstance;
|
||||
@@ -272,11 +318,13 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).
|
||||
append("testClass", this.testClass).
|
||||
append("locations", this.locations).append("testInstance", this.testInstance).
|
||||
append("testMethod", this.testMethod).append("testException", this.testException).
|
||||
toString();
|
||||
return new ToStringCreator(this)//
|
||||
.append("testClass", this.testClass)//
|
||||
.append("locations", this.locations)//
|
||||
.append("testInstance", this.testInstance)//
|
||||
.append("testMethod", this.testMethod)//
|
||||
.append("testException", this.testException)//
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -35,15 +34,15 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* <p>
|
||||
* <code>TestContextManager</code> is the main entry point into the
|
||||
* <em>Spring TestContext Framework</em>, which provides support for loading
|
||||
* and accessing {@link ApplicationContext application contexts}, dependency
|
||||
* <em>Spring TestContext Framework</em>, which provides support for loading and
|
||||
* accessing {@link ApplicationContext application contexts}, dependency
|
||||
* injection of test instances,
|
||||
* {@link org.springframework.transaction.annotation.Transactional transactional}
|
||||
* execution of test methods, etc.
|
||||
* {@link org.springframework.transaction.annotation.Transactional
|
||||
* transactional} execution of test methods, etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Specifically, a <code>TestContextManager</code> is responsible for managing
|
||||
* a single {@link TestContext} and signaling events to all registered
|
||||
* Specifically, a <code>TestContextManager</code> is responsible for managing a
|
||||
* single {@link TestContext} and signaling events to all registered
|
||||
* {@link TestExecutionListener TestExecutionListeners} at well defined test
|
||||
* execution points:
|
||||
* </p>
|
||||
@@ -51,13 +50,13 @@ import org.springframework.util.Assert;
|
||||
* <li>{@link #prepareTestInstance(Object) test instance preparation}:
|
||||
* immediately following instantiation of the test instance</li>
|
||||
* <li>{@link #beforeTestMethod(Object,Method) before test method execution}:
|
||||
* prior to any <em>before methods</em> of a particular testing framework
|
||||
* (e.g., JUnit 4's {@link org.junit.Before @Before})</li>
|
||||
* <li>{@link #afterTestMethod(Object,Method,Throwable) after test method execution}:
|
||||
* after any <em>after methods</em> of a particular testing framework (e.g.,
|
||||
* JUnit 4's {@link org.junit.After @After})</li>
|
||||
* prior to any <em>before methods</em> of a particular testing framework (e.g.,
|
||||
* JUnit 4's {@link org.junit.Before @Before})</li>
|
||||
* <li>{@link #afterTestMethod(Object,Method,Throwable) after test method
|
||||
* execution}: after any <em>after methods</em> of a particular testing
|
||||
* framework (e.g., JUnit 4's {@link org.junit.After @After})</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
@@ -69,9 +68,9 @@ import org.springframework.util.Assert;
|
||||
public class TestContextManager {
|
||||
|
||||
private static final String[] DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES = new String[] {
|
||||
"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
|
||||
"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
|
||||
"org.springframework.test.context.transaction.TransactionalTestExecutionListener" };
|
||||
"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
|
||||
"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
|
||||
"org.springframework.test.context.transaction.TransactionalTestExecutionListener" };
|
||||
|
||||
private static final Log logger = LogFactory.getLog(TestContextManager.class);
|
||||
|
||||
@@ -82,41 +81,50 @@ public class TestContextManager {
|
||||
*/
|
||||
static final ContextCache contextCache = new ContextCache();
|
||||
|
||||
|
||||
private final TestContext testContext;
|
||||
|
||||
private final List<TestExecutionListener> testExecutionListeners = new ArrayList<TestExecutionListener>();
|
||||
|
||||
|
||||
/**
|
||||
* Delegates to {@link #TestContextManager(Class, String)} with a value of
|
||||
* <code>null</code> for the default <code>ContextLoader</code> class name.
|
||||
*/
|
||||
public TestContextManager(Class<?> testClass) {
|
||||
this(testClass, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>TestContextManager</code> for the specified
|
||||
* {@link Class test class} and automatically
|
||||
* {@link #registerTestExecutionListeners(TestExecutionListener...) registers}
|
||||
* the {@link TestExecutionListener TestExecutionListeners} configured for
|
||||
* the test class via the
|
||||
* {@link TestExecutionListeners @TestExecutionListeners} annotation.
|
||||
* @param testClass the Class object corresponding to the test class to be managed
|
||||
* {@link #registerTestExecutionListeners(TestExecutionListener...)
|
||||
* registers} the {@link TestExecutionListener TestExecutionListeners}
|
||||
* configured for the test class via the {@link TestExecutionListeners
|
||||
* @TestExecutionListeners} annotation.
|
||||
*
|
||||
* @param testClass the test class to be managed
|
||||
* @param defaultContextLoaderClassName the name of the default
|
||||
* <code>ContextLoader</code> class to use (may be <code>null</code>)
|
||||
* @see #registerTestExecutionListeners(TestExecutionListener...)
|
||||
* @see #retrieveTestExecutionListeners(Class)
|
||||
*/
|
||||
public TestContextManager(Class<?> testClass) {
|
||||
this.testContext = new TestContext(testClass, contextCache);
|
||||
public TestContextManager(Class<?> testClass, String defaultContextLoaderClassName) {
|
||||
this.testContext = new TestContext(testClass, contextCache, defaultContextLoaderClassName);
|
||||
registerTestExecutionListeners(retrieveTestExecutionListeners(testClass));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the {@link TestContext} managed by this <code>TestContextManager</code>.
|
||||
* Returns the {@link TestContext} managed by this
|
||||
* <code>TestContextManager</code>.
|
||||
*/
|
||||
protected final TestContext getTestContext() {
|
||||
return this.testContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register the supplied
|
||||
* {@link TestExecutionListener TestExecutionListeners} by appending them to
|
||||
* the set of listeners used by this <code>TestContextManager</code>.
|
||||
* Register the supplied {@link TestExecutionListener
|
||||
* TestExecutionListeners} by appending them to the set of listeners used by
|
||||
* this <code>TestContextManager</code>.
|
||||
*/
|
||||
public void registerTestExecutionListeners(TestExecutionListener... testExecutionListeners) {
|
||||
for (TestExecutionListener listener : testExecutionListeners) {
|
||||
@@ -137,27 +145,26 @@ public class TestContextManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an array of newly instantiated
|
||||
* {@link TestExecutionListener TestExecutionListeners} for the specified
|
||||
* {@link Class class}. If
|
||||
* {@link TestExecutionListeners @TestExecutionListeners} is not
|
||||
* Retrieves an array of newly instantiated {@link TestExecutionListener
|
||||
* TestExecutionListeners} for the specified {@link Class class}. If
|
||||
* {@link TestExecutionListeners @TestExecutionListeners} is not
|
||||
* <em>present</em> on the supplied class, the default listeners will be
|
||||
* returned.
|
||||
* <p>Note that the
|
||||
* {@link TestExecutionListeners#inheritListeners() inheritListeners} flag
|
||||
* of {@link TestExecutionListeners @TestExecutionListeners} will be taken
|
||||
* into consideration. Specifically, if the <code>inheritListeners</code>
|
||||
* flag is set to <code>true</code>, listeners defined in the annotated
|
||||
* class will be appended to the listeners defined in superclasses.
|
||||
* @param clazz the Class object corresponding to the test class for which
|
||||
* the listeners should be retrieved
|
||||
* <p>
|
||||
* Note that the {@link TestExecutionListeners#inheritListeners()
|
||||
* inheritListeners} flag of {@link TestExecutionListeners
|
||||
* @TestExecutionListeners} will be taken into consideration.
|
||||
* Specifically, if the <code>inheritListeners</code> flag is set to
|
||||
* <code>true</code>, listeners defined in the annotated class will be
|
||||
* appended to the listeners defined in superclasses.
|
||||
*
|
||||
* @param clazz the test class for which the listeners should be retrieved
|
||||
* @return an array of TestExecutionListeners for the specified class
|
||||
*/
|
||||
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>>();
|
||||
List<Class<? extends TestExecutionListener>> classesList = new ArrayList<Class<? extends TestExecutionListener>>();
|
||||
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
|
||||
boolean defaultListeners = false;
|
||||
|
||||
@@ -181,8 +188,9 @@ public class TestContextManager {
|
||||
if (classes != null) {
|
||||
classesList.addAll(0, Arrays.<Class<? extends TestExecutionListener>> asList(classes));
|
||||
}
|
||||
declaringClass = (testExecutionListeners.inheritListeners() ?
|
||||
AnnotationUtils.findAnnotationDeclaringClass(annotationType, declaringClass.getSuperclass()) : null);
|
||||
declaringClass = (testExecutionListeners.inheritListeners() ? AnnotationUtils.findAnnotationDeclaringClass(
|
||||
annotationType, declaringClass.getSuperclass())
|
||||
: null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +202,8 @@ public class TestContextManager {
|
||||
catch (NoClassDefFoundError err) {
|
||||
if (defaultListeners) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not instantiate default TestExecutionListener class [" + listenerClass.getName()
|
||||
logger.debug("Could not instantiate default TestExecutionListener class ["
|
||||
+ listenerClass.getName()
|
||||
+ "]. Specify custom listener classes or make the default listener classes available.");
|
||||
}
|
||||
}
|
||||
@@ -211,12 +220,11 @@ public class TestContextManager {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Set<Class<? extends TestExecutionListener>> getDefaultTestExecutionListenerClasses() {
|
||||
Set<Class<? extends TestExecutionListener>> defaultListenerClasses =
|
||||
new LinkedHashSet<Class<? extends TestExecutionListener>>();
|
||||
Set<Class<? extends TestExecutionListener>> defaultListenerClasses = new LinkedHashSet<Class<? extends TestExecutionListener>>();
|
||||
for (String className : DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES) {
|
||||
try {
|
||||
defaultListenerClasses.add(
|
||||
(Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(className));
|
||||
defaultListenerClasses.add((Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(
|
||||
className));
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -228,19 +236,23 @@ public class TestContextManager {
|
||||
return defaultListenerClasses;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hook for preparing a test instance prior to execution of any individual
|
||||
* test methods, for example for injecting dependencies, etc. Should be
|
||||
* called immediately after instantiation of the test instance.
|
||||
* <p>The managed {@link TestContext} will be updated with the supplied
|
||||
* <p>
|
||||
* The managed {@link TestContext} will be updated with the supplied
|
||||
* <code>testInstance</code>.
|
||||
* <p>An attempt will be made to give each registered
|
||||
* <p>
|
||||
* An attempt will be made to give each registered
|
||||
* {@link TestExecutionListener} a chance to prepare the test instance. If a
|
||||
* listener throws an exception, however, the remaining registered listeners
|
||||
* will <strong>not</strong> be called.
|
||||
* @param testInstance the test instance to prepare (never <code>null</code>)
|
||||
* @throws Exception if a registered TestExecutionListener throws an exception
|
||||
*
|
||||
* @param testInstance the test instance to prepare (never <code>null</code>
|
||||
* )
|
||||
* @throws Exception if a registered TestExecutionListener throws an
|
||||
* exception
|
||||
* @see #getTestExecutionListeners()
|
||||
*/
|
||||
public void prepareTestInstance(Object testInstance) throws Exception {
|
||||
@@ -263,21 +275,25 @@ public class TestContextManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for pre-processing a test <em>before</em> execution of the
|
||||
* supplied {@link Method test method}, for example for setting up test
|
||||
* fixtures, starting a transaction, etc. Should be called prior to any
|
||||
* framework-specific <em>before methods</em> (e.g., methods annotated
|
||||
* with JUnit's {@link org.junit.Before @Before} ).
|
||||
* <p>The managed {@link TestContext} will be updated with the supplied
|
||||
* Hook for pre-processing a test <em>before</em> execution of the supplied
|
||||
* {@link Method test method}, for example for setting up test fixtures,
|
||||
* starting a transaction, etc. Should be called prior to any
|
||||
* framework-specific <em>before methods</em> (e.g., methods annotated with
|
||||
* JUnit's {@link org.junit.Before @Before} ).
|
||||
* <p>
|
||||
* The managed {@link TestContext} will be updated with the supplied
|
||||
* <code>testInstance</code> and <code>testMethod</code>.
|
||||
* <p>An attempt will be made to give each registered
|
||||
* <p>
|
||||
* An attempt will be made to give each registered
|
||||
* {@link TestExecutionListener} a chance to pre-process the test method
|
||||
* execution. If a listener throws an exception, however, the remaining
|
||||
* registered listeners will <strong>not</strong> be called.
|
||||
*
|
||||
* @param testInstance the current test instance (never <code>null</code>)
|
||||
* @param testMethod the test method which is about to be executed on the
|
||||
* test instance
|
||||
* @throws Exception if a registered TestExecutionListener throws an exception
|
||||
* @throws Exception if a registered TestExecutionListener throws an
|
||||
* exception
|
||||
* @see #getTestExecutionListeners()
|
||||
*/
|
||||
public void beforeTestMethod(Object testInstance, Method testMethod) throws Exception {
|
||||
@@ -301,41 +317,45 @@ public class TestContextManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for post-processing a test <em>after</em> execution of the
|
||||
* supplied {@link Method test method}, for example for tearing down test
|
||||
* fixtures, ending a transaction, etc. Should be called after any
|
||||
* framework-specific <em>after methods</em> (e.g., methods annotated with
|
||||
* JUnit's {@link org.junit.After @After}).
|
||||
* <p>The managed {@link TestContext} will be updated with the supplied
|
||||
* Hook for post-processing a test <em>after</em> execution of the supplied
|
||||
* {@link Method test method}, for example for tearing down test fixtures,
|
||||
* ending a transaction, etc. Should be called after any framework-specific
|
||||
* <em>after methods</em> (e.g., methods annotated with JUnit's
|
||||
* {@link org.junit.After @After}).
|
||||
* <p>
|
||||
* The managed {@link TestContext} will be updated with the supplied
|
||||
* <code>testInstance</code>, <code>testMethod</code>, and
|
||||
* <code>exception</code>.
|
||||
* <p>Each registered {@link TestExecutionListener} will be given a chance to
|
||||
* <p>
|
||||
* Each registered {@link TestExecutionListener} will be given a chance to
|
||||
* post-process the test method execution. If a listener throws an
|
||||
* exception, the remaining registered listeners will still be called, but
|
||||
* the first exception thrown will be tracked and rethrown after all
|
||||
* listeners have executed. Note that registered listeners will be executed
|
||||
* in the opposite order in which they were registered.
|
||||
*
|
||||
* @param testInstance the current test instance (never <code>null</code>)
|
||||
* @param testMethod the test method which has just been executed on the
|
||||
* test instance
|
||||
* @param exception the exception that was thrown during execution of the
|
||||
* test method or by a TestExecutionListener, or <code>null</code>
|
||||
* if none was thrown
|
||||
* @throws Exception if a registered TestExecutionListener throws an exception
|
||||
* test method or by a TestExecutionListener, or <code>null</code> if none
|
||||
* was thrown
|
||||
* @throws Exception if a registered TestExecutionListener throws an
|
||||
* exception
|
||||
* @see #getTestExecutionListeners()
|
||||
*/
|
||||
public void afterTestMethod(Object testInstance, Method testMethod, Throwable exception) throws Exception {
|
||||
Assert.notNull(testInstance, "testInstance must not be null");
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("afterTestMethod(): instance [" + testInstance + "], method [" + testMethod +
|
||||
"], exception [" + exception + "]");
|
||||
logger.trace("afterTestMethod(): instance [" + testInstance + "], method [" + testMethod + "], exception ["
|
||||
+ exception + "]");
|
||||
}
|
||||
getTestContext().updateState(testInstance, testMethod, exception);
|
||||
|
||||
// Traverse the TestExecutionListeners in reverse order to ensure proper
|
||||
// "wrapper"-style execution of listeners.
|
||||
List<TestExecutionListener> listenersReversed =
|
||||
new ArrayList<TestExecutionListener>(getTestExecutionListeners());
|
||||
List<TestExecutionListener> listenersReversed = new ArrayList<TestExecutionListener>(
|
||||
getTestExecutionListeners());
|
||||
Collections.reverse(listenersReversed);
|
||||
|
||||
Exception afterTestMethodException = null;
|
||||
@@ -344,9 +364,9 @@ public class TestContextManager {
|
||||
testExecutionListener.afterTestMethod(getTestContext());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener +
|
||||
"] to process 'after' execution for test: method [" + testMethod + "], instance [" +
|
||||
testInstance + "], exception [" + exception + "]", ex);
|
||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||
+ "] to process 'after' execution for test: method [" + testMethod + "], instance ["
|
||||
+ testInstance + "], exception [" + exception + "]", ex);
|
||||
if (afterTestMethodException == null) {
|
||||
afterTestMethodException = ex;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
|
||||
* {@link TestContextManager} to provide Spring testing functionality to
|
||||
* standard JUnit tests.
|
||||
*
|
||||
* @param clazz the Class object corresponding to the test class to be run
|
||||
* @param clazz the test class to be run
|
||||
* @see #createTestContextManager(Class)
|
||||
*/
|
||||
public SpringJUnit4ClassRunner(Class<?> clazz) throws InitializationError {
|
||||
@@ -106,14 +106,15 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TestContextManager}. Can be overridden by
|
||||
* subclasses.
|
||||
* Creates a new {@link TestContextManager} for the supplied test class and
|
||||
* the configured <em>default <code>ContextLoader</code> class name</em>.
|
||||
* Can be overridden by subclasses.
|
||||
*
|
||||
* @param clazz the Class object corresponding to the test class to be
|
||||
* managed
|
||||
* @param clazz the test class to be managed
|
||||
* @see #getDefaultContextLoaderClassName(Class)
|
||||
*/
|
||||
protected TestContextManager createTestContextManager(Class<?> clazz) {
|
||||
return new TestContextManager(clazz);
|
||||
return new TestContextManager(clazz, getDefaultContextLoaderClassName(clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,6 +124,24 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
|
||||
return this.testContextManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the default <code>ContextLoader</code> class to use for
|
||||
* the supplied test class. The named class will be used if the test class
|
||||
* does not explicitly declare a <code>ContextLoader</code> class via the
|
||||
* <code>@ContextConfiguration</code> annotation.
|
||||
* <p>
|
||||
* The default implementation returns <code>null</code>, thus implying use
|
||||
* of the <em>standard</em> default <code>ContextLoader</code> class name.
|
||||
* Can be overridden by subclasses.
|
||||
* </p>
|
||||
*
|
||||
* @param clazz the test class
|
||||
* @return <code>null</code>
|
||||
*/
|
||||
protected String getDefaultContextLoaderClassName(Class<?> clazz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the parent implementation for creating the test instance and
|
||||
* then allows the {@link #getTestContextManager() TestContextManager} to
|
||||
|
||||
Reference in New Issue
Block a user