diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/TestContext.java b/org.springframework.test/src/main/java/org/springframework/test/context/TestContext.java index 1775c59a0f5..65d5555ea51 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/TestContext.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/TestContext.java @@ -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 null for the default ContextLoader + * 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 null) - * @param contextCache the context cache from which the constructed test context - * should retrieve application contexts (must not be null) + * and {@link ContextCache context cache} and parse the corresponding + * {@link ContextConfiguration @ContextConfiguration} annotation, if + * present. + *

+ * If the supplied class name for the default ContextLoader is + * null or empty and no ContextLoader + * class is explicitly supplied via the + * @ContextConfiguration annotation, a + * {@link org.springframework.test.context.support.GenericXmlContextLoader + * GenericXmlContextLoader} will be used instead. + *

+ * + * @param testClass the test class for which the test context should be + * constructed (must not be null) + * @param contextCache the context cache from which the constructed test + * context should retrieve application contexts (must not be + * null) + * @param defaultContextLoaderClassName the name of the default + * ContextLoader class to use (may be null) */ @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 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) 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. - *

Note that the - * {@link ContextConfiguration#inheritLocations() inheritLocations} flag of - * {@link ContextConfiguration @ContextConfiguration} will be taken into - * consideration. Specifically, if the inheritLocations flag - * is set to true, 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 null) - * @param clazz the class for which to retrieve the resource locations - * (must not be null) - * @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 present on the supplied class + * {@link ContextLoader#processLocations(Class, String...) process} the + * locations. + *

+ * Note that the {@link ContextConfiguration#inheritLocations() + * inheritLocations} flag of {@link ContextConfiguration + * @ContextConfiguration} will be taken into consideration. + * Specifically, if the inheritLocations flag is set to + * true, 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 null) + * + * @param clazz the class for which to retrieve the resource locations (must + * not be null) + * @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 present 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 locationsList = new ArrayList(); Class 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. 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 key to a String - * representation for use in caching, logging, etc. + * Convert the supplied context key 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 null 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 null 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 null) */ public final Class getTestClass() { @@ -214,7 +252,9 @@ public class TestContext extends AttributeAccessorSupport { /** * Get the current {@link Object test instance} for this test context. - *

Note: this is a mutable property. + *

+ * Note: this is a mutable property. + * * @return the current test instance (may be null) * @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. - *

Note: this is a mutable property. + *

+ * Note: this is a mutable property. + * * @return the current test method (may be null) * @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}. - *

Note: this is a mutable property. + *

+ * Note: this is a mutable property. + * * @return the exception that was thrown, or null 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 dirty 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 dirty 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 null) * @param testMethod the current test method (may be null) - * @param testException the exception that was thrown in the test method, - * or null if no exception was thrown + * @param testException the exception that was thrown in the test method, or + * null 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(); } } diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/TestContextManager.java b/org.springframework.test/src/main/java/org/springframework/test/context/TestContextManager.java index 4dc654de1a7..d77ecf6b183 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/TestContextManager.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/TestContextManager.java @@ -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; /** *

* TestContextManager is the main entry point into the - * Spring TestContext Framework, which provides support for loading - * and accessing {@link ApplicationContext application contexts}, dependency + * Spring TestContext Framework, 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. *

*

- * Specifically, a TestContextManager is responsible for managing - * a single {@link TestContext} and signaling events to all registered + * Specifically, a TestContextManager is responsible for managing a + * single {@link TestContext} and signaling events to all registered * {@link TestExecutionListener TestExecutionListeners} at well defined test * execution points: *

@@ -51,13 +50,13 @@ import org.springframework.util.Assert; *
  • {@link #prepareTestInstance(Object) test instance preparation}: * immediately following instantiation of the test instance
  • *
  • {@link #beforeTestMethod(Object,Method) before test method execution}: - * prior to any before methods of a particular testing framework - * (e.g., JUnit 4's {@link org.junit.Before @Before})
  • - *
  • {@link #afterTestMethod(Object,Method,Throwable) after test method execution}: - * after any after methods of a particular testing framework (e.g., - * JUnit 4's {@link org.junit.After @After})
  • + * prior to any before methods of a particular testing framework (e.g., + * JUnit 4's {@link org.junit.Before @Before}) + *
  • {@link #afterTestMethod(Object,Method,Throwable) after test method + * execution}: after any after methods of a particular testing + * framework (e.g., JUnit 4's {@link org.junit.After @After})
  • * - * + * * @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 testExecutionListeners = new ArrayList(); + /** + * Delegates to {@link #TestContextManager(Class, String)} with a value of + * null for the default ContextLoader class name. + */ + public TestContextManager(Class testClass) { + this(testClass, null); + } + /** * Constructs a new TestContextManager 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 + * ContextLoader class to use (may be null) * @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 TestContextManager. + * Returns the {@link TestContext} managed by this + * TestContextManager. */ protected final TestContext getTestContext() { return this.testContext; } - /** - * Register the supplied - * {@link TestExecutionListener TestExecutionListeners} by appending them to - * the set of listeners used by this TestContextManager. + * Register the supplied {@link TestExecutionListener + * TestExecutionListeners} by appending them to the set of listeners used by + * this TestContextManager. */ 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 * present on the supplied class, the default listeners will be * returned. - *

    Note that the - * {@link TestExecutionListeners#inheritListeners() inheritListeners} flag - * of {@link TestExecutionListeners @TestExecutionListeners} will be taken - * into consideration. Specifically, if the inheritListeners - * flag is set to true, 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 + *

    + * Note that the {@link TestExecutionListeners#inheritListeners() + * inheritListeners} flag of {@link TestExecutionListeners + * @TestExecutionListeners} will be taken into consideration. + * Specifically, if the inheritListeners flag is set to + * true, 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 annotationType = TestExecutionListeners.class; - List> classesList = - new ArrayList>(); + List> classesList = new ArrayList>(); Class declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz); boolean defaultListeners = false; @@ -181,8 +188,9 @@ public class TestContextManager { if (classes != null) { classesList.addAll(0, Arrays.> 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> getDefaultTestExecutionListenerClasses() { - Set> defaultListenerClasses = - new LinkedHashSet>(); + Set> defaultListenerClasses = new LinkedHashSet>(); for (String className : DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES) { try { - defaultListenerClasses.add( - (Class) getClass().getClassLoader().loadClass(className)); + defaultListenerClasses.add((Class) 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. - *

    The managed {@link TestContext} will be updated with the supplied + *

    + * The managed {@link TestContext} will be updated with the supplied * testInstance. - *

    An attempt will be made to give each registered + *

    + * 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 not be called. - * @param testInstance the test instance to prepare (never null) - * @throws Exception if a registered TestExecutionListener throws an exception + * + * @param testInstance the test instance to prepare (never null + * ) + * @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 before 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 before methods (e.g., methods annotated - * with JUnit's {@link org.junit.Before @Before} ). - *

    The managed {@link TestContext} will be updated with the supplied + * Hook for pre-processing a test before 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 before methods (e.g., methods annotated with + * JUnit's {@link org.junit.Before @Before} ). + *

    + * The managed {@link TestContext} will be updated with the supplied * testInstance and testMethod. - *

    An attempt will be made to give each registered + *

    + * 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 not be called. + * * @param testInstance the current test instance (never null) * @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 after 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 after methods (e.g., methods annotated with - * JUnit's {@link org.junit.After @After}). - *

    The managed {@link TestContext} will be updated with the supplied + * Hook for post-processing a test after 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 + * after methods (e.g., methods annotated with JUnit's + * {@link org.junit.After @After}). + *

    + * The managed {@link TestContext} will be updated with the supplied * testInstance, testMethod, and * exception. - *

    Each registered {@link TestExecutionListener} will be given a chance to + *

    + * 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 null) * @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 null - * if none was thrown - * @throws Exception if a registered TestExecutionListener throws an exception + * test method or by a TestExecutionListener, or null 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 listenersReversed = - new ArrayList(getTestExecutionListeners()); + List listenersReversed = new ArrayList( + 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; } diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java index 986600cf901..cab324b59e7 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java @@ -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 default ContextLoader class name. + * 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 ContextLoader class to use for + * the supplied test class. The named class will be used if the test class + * does not explicitly declare a ContextLoader class via the + * @ContextConfiguration annotation. + *

    + * The default implementation returns null, thus implying use + * of the standard default ContextLoader class name. + * Can be overridden by subclasses. + *

    + * + * @param clazz the test class + * @return null + */ + 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 diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/CustomDefaultContextLoaderClassSpringRunnerTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/CustomDefaultContextLoaderClassSpringRunnerTests.java new file mode 100644 index 00000000000..ef440f13ff6 --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/CustomDefaultContextLoaderClassSpringRunnerTests.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2009 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.model.InitializationError; +import org.springframework.beans.Pet; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.support.GenericPropertiesContextLoader; + +/** + * Unit tests which verify that a subclass of {@link SpringJUnit4ClassRunner} + * can specify a custom default ContextLoader class name that overrides + * the standard default class name. + * + * @author Sam Brannen + * @since 3.0 + */ +@RunWith(CustomDefaultContextLoaderClassSpringRunnerTests.PropertiesBasedSpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests-context.properties") +public class CustomDefaultContextLoaderClassSpringRunnerTests { + + @Autowired + private Pet cat; + + @Autowired + private String testString; + + + @Test + public void verifyAnnotationAutowiredFields() { + assertNotNull("The cat field should have been autowired.", this.cat); + assertEquals("Garfield", this.cat.getName()); + + assertNotNull("The testString field should have been autowired.", this.testString); + assertEquals("Test String", this.testString); + } + + + public static final class PropertiesBasedSpringJUnit4ClassRunner extends SpringJUnit4ClassRunner { + + public PropertiesBasedSpringJUnit4ClassRunner(Class clazz) throws InitializationError { + super(clazz); + } + + @Override + protected String getDefaultContextLoaderClassName(Class clazz) { + return GenericPropertiesContextLoader.class.getName(); + } + + } +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java index 7d2289a5a64..d57f39ba27e 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java @@ -57,6 +57,7 @@ StandardJUnit4FeaturesTests.class,// MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.class,// InheritedConfigSpringJUnit4ClassRunnerAppCtxTests.class,// PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests.class,// + CustomDefaultContextLoaderClassSpringRunnerTests.class,// SpringRunnerContextCacheTests.class,// ParameterizedDependencyInjectionTests.class,// ClassLevelTransactionalSpringRunnerTests.class,//