From 3f0462510e4edefc7d6ef830b0ea61e1ff623fd4 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 2 Oct 2010 01:05:40 +0000 Subject: [PATCH] getTestExecutionListeners() returns actual List which allows for iteration as well as modification (SPR-7595) --- .../test/context/TestContextManager.java | 119 +++++++----------- 1 file changed, 48 insertions(+), 71 deletions(-) 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 e463c325f0e..8e215376322 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -26,6 +26,7 @@ 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; @@ -102,13 +103,10 @@ public class TestContextManager { } /** - * 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. - * + * Constructs a new TestContextManager for the specified {@link Class test class} + * and automatically {@link #registerTestExecutionListeners 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) @@ -128,54 +126,49 @@ public class TestContextManager { 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) { if (logger.isTraceEnabled()) { - logger.trace("Registering TestExecutionListener [" + listener + "]"); + logger.trace("Registering TestExecutionListener: " + listener); } this.testExecutionListeners.add(listener); } } /** - * Gets an {@link Collections#unmodifiableList(List) unmodifiable} copy of - * the {@link TestExecutionListener TestExecutionListeners} registered for - * this TestContextManager. + * Get the current {@link TestExecutionListener TestExecutionListeners} + * registered for this TestContextManager. + *

Allows for modifications, e.g. adding a listener to the beginning of the list. + * However, make sure to keep the list stable while actually executing tests. */ public final List getTestExecutionListeners() { - return Collections.unmodifiableList(this.testExecutionListeners); + return this.testExecutionListeners; } /** - * Gets a copy of the {@link TestExecutionListener TestExecutionListeners} + * Get a copy of the {@link TestExecutionListener TestExecutionListeners} * registered for this TestContextManager in reverse order. */ private List getReversedTestExecutionListeners() { - List listenersReversed = new ArrayList( - getTestExecutionListeners()); + List listenersReversed = + new ArrayList(getTestExecutionListeners()); Collections.reverse(listenersReversed); return listenersReversed; } /** - * 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. - * + * Retrieve 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 test class for which the listeners should be retrieved * @return an array of TestExecutionListeners for the specified class */ @@ -207,7 +200,8 @@ public class TestContextManager { Class[] listenerClasses = testExecutionListeners.listeners(); if (!ObjectUtils.isEmpty(valueListenerClasses) && !ObjectUtils.isEmpty(listenerClasses)) { String msg = String.format( - "Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] and 'listeners' [%s] attributes. Use one or the other, but not both.", + "Test 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)); logger.error(msg); @@ -220,16 +214,15 @@ public class TestContextManager { if (listenerClasses != null) { classesList.addAll(0, Arrays.> asList(listenerClasses)); } - declaringClass = (testExecutionListeners.inheritListeners() ? AnnotationUtils.findAnnotationDeclaringClass( - annotationType, declaringClass.getSuperclass()) - : null); + declaringClass = (testExecutionListeners.inheritListeners() ? + AnnotationUtils.findAnnotationDeclaringClass(annotationType, declaringClass.getSuperclass()) : null); } } List listeners = new ArrayList(classesList.size()); for (Class listenerClass : classesList) { try { - listeners.add((TestExecutionListener) BeanUtils.instantiateClass(listenerClass)); + listeners.add(BeanUtils.instantiateClass(listenerClass)); } catch (NoClassDefFoundError err) { if (defaultListeners) { @@ -252,11 +245,12 @@ 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()) { @@ -268,17 +262,16 @@ public class TestContextManager { return defaultListenerClasses; } + /** * Hook for pre-processing a test class before execution of any * tests within the class. Should be called prior to any framework-specific * before class methods (e.g., methods annotated with JUnit's * {@link org.junit.BeforeClass @BeforeClass}). - *

- * 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 class * execution. If a listener throws an exception, however, the remaining * registered listeners will not be called. - * * @throws Exception if a registered TestExecutionListener throws an * exception * @see #getTestExecutionListeners() @@ -306,19 +299,14 @@ public class TestContextManager { * 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 { @@ -346,20 +334,16 @@ public class TestContextManager { * 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 + *

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 { @@ -388,26 +372,22 @@ public class TestContextManager { * 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 + *

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 + * @throws Exception if a registered TestExecutionListener throws an exception * @see #getTestExecutionListeners() */ public void afterTestMethod(Object testInstance, Method testMethod, Throwable exception) throws Exception { @@ -444,16 +424,13 @@ public class TestContextManager { * tests within the class. Should be called after any framework-specific * after class methods (e.g., methods annotated with JUnit's * {@link org.junit.AfterClass @AfterClass}). - *

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

Each registered {@link TestExecutionListener} will be given a chance to * post-process the test class. 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. - * - * @throws Exception if a registered TestExecutionListener throws an - * exception + * @throws Exception if a registered TestExecutionListener throws an exception * @see #getTestExecutionListeners() */ public void afterTestClass() throws Exception {