Skip to content

Commit 3f04625

Browse files
committed
getTestExecutionListeners() returns actual List which allows for iteration as well as modification (SPR-7595)
1 parent 40fa8af commit 3f04625

File tree

1 file changed

+48
-71
lines changed

1 file changed

+48
-71
lines changed

org.springframework.test/src/main/java/org/springframework/test/context/TestContextManager.java

Lines changed: 48 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
2626

2727
import org.apache.commons.logging.Log;
2828
import org.apache.commons.logging.LogFactory;
29+
2930
import org.springframework.beans.BeanUtils;
3031
import org.springframework.context.ApplicationContext;
3132
import org.springframework.core.annotation.AnnotationUtils;
@@ -102,13 +103,10 @@ public TestContextManager(Class<?> testClass) {
102103
}
103104

104105
/**
105-
* Constructs a new <code>TestContextManager</code> for the specified
106-
* {@link Class test class} and automatically
107-
* {@link #registerTestExecutionListeners(TestExecutionListener...)
108-
* registers} the {@link TestExecutionListener TestExecutionListeners}
109-
* configured for the test class via the {@link TestExecutionListeners
110-
* &#064;TestExecutionListeners} annotation.
111-
*
106+
* Constructs a new <code>TestContextManager</code> for the specified {@link Class test class}
107+
* and automatically {@link #registerTestExecutionListeners registers} the
108+
* {@link TestExecutionListener TestExecutionListeners} configured for the test class
109+
* via the {@link TestExecutionListeners &#064;TestExecutionListeners} annotation.
112110
* @param testClass the test class to be managed
113111
* @param defaultContextLoaderClassName the name of the default
114112
* <code>ContextLoader</code> class to use (may be <code>null</code>)
@@ -128,54 +126,49 @@ protected final TestContext getTestContext() {
128126
return this.testContext;
129127
}
130128

129+
131130
/**
132-
* Register the supplied {@link TestExecutionListener
133-
* TestExecutionListeners} by appending them to the set of listeners used by
134-
* this <code>TestContextManager</code>.
131+
* Register the supplied {@link TestExecutionListener TestExecutionListeners}
132+
* by appending them to the set of listeners used by this <code>TestContextManager</code>.
135133
*/
136134
public void registerTestExecutionListeners(TestExecutionListener... testExecutionListeners) {
137135
for (TestExecutionListener listener : testExecutionListeners) {
138136
if (logger.isTraceEnabled()) {
139-
logger.trace("Registering TestExecutionListener [" + listener + "]");
137+
logger.trace("Registering TestExecutionListener: " + listener);
140138
}
141139
this.testExecutionListeners.add(listener);
142140
}
143141
}
144142

145143
/**
146-
* Gets an {@link Collections#unmodifiableList(List) unmodifiable} copy of
147-
* the {@link TestExecutionListener TestExecutionListeners} registered for
148-
* this <code>TestContextManager</code>.
144+
* Get the current {@link TestExecutionListener TestExecutionListeners}
145+
* registered for this <code>TestContextManager</code>.
146+
* <p>Allows for modifications, e.g. adding a listener to the beginning of the list.
147+
* However, make sure to keep the list stable while actually executing tests.
149148
*/
150149
public final List<TestExecutionListener> getTestExecutionListeners() {
151-
return Collections.unmodifiableList(this.testExecutionListeners);
150+
return this.testExecutionListeners;
152151
}
153152

154153
/**
155-
* Gets a copy of the {@link TestExecutionListener TestExecutionListeners}
154+
* Get a copy of the {@link TestExecutionListener TestExecutionListeners}
156155
* registered for this <code>TestContextManager</code> in reverse order.
157156
*/
158157
private List<TestExecutionListener> getReversedTestExecutionListeners() {
159-
List<TestExecutionListener> listenersReversed = new ArrayList<TestExecutionListener>(
160-
getTestExecutionListeners());
158+
List<TestExecutionListener> listenersReversed =
159+
new ArrayList<TestExecutionListener>(getTestExecutionListeners());
161160
Collections.reverse(listenersReversed);
162161
return listenersReversed;
163162
}
164163

165164
/**
166-
* Retrieves an array of newly instantiated {@link TestExecutionListener
167-
* TestExecutionListeners} for the specified {@link Class class}. If
168-
* {@link TestExecutionListeners &#064;TestExecutionListeners} is not
169-
* <em>present</em> on the supplied class, the default listeners will be
170-
* returned.
171-
* <p>
172-
* Note that the {@link TestExecutionListeners#inheritListeners()
173-
* inheritListeners} flag of {@link TestExecutionListeners
174-
* &#064;TestExecutionListeners} will be taken into consideration.
175-
* Specifically, if the <code>inheritListeners</code> flag is set to
176-
* <code>true</code>, listeners defined in the annotated class will be
177-
* appended to the listeners defined in superclasses.
178-
*
165+
* Retrieve an array of newly instantiated {@link TestExecutionListener TestExecutionListeners}
166+
* for the specified {@link Class class}. If {@link TestExecutionListeners &#064;TestExecutionListeners}
167+
* is not <em>present</em> on the supplied class, the default listeners will be returned.
168+
* <p>Note that the {@link TestExecutionListeners#inheritListeners() inheritListeners} flag of
169+
* {@link TestExecutionListeners &#064;TestExecutionListeners} will be taken into consideration.
170+
* Specifically, if the <code>inheritListeners</code> flag is set to <code>true</code>, listeners
171+
* defined in the annotated class will be appended to the listeners defined in superclasses.
179172
* @param clazz the test class for which the listeners should be retrieved
180173
* @return an array of TestExecutionListeners for the specified class
181174
*/
@@ -207,7 +200,8 @@ private TestExecutionListener[] retrieveTestExecutionListeners(Class<?> clazz) {
207200
Class<? extends TestExecutionListener>[] listenerClasses = testExecutionListeners.listeners();
208201
if (!ObjectUtils.isEmpty(valueListenerClasses) && !ObjectUtils.isEmpty(listenerClasses)) {
209202
String msg = String.format(
210-
"Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] and 'listeners' [%s] attributes. Use one or the other, but not both.",
203+
"Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] " +
204+
"and 'listeners' [%s] attributes. Use one or the other, but not both.",
211205
declaringClass, ObjectUtils.nullSafeToString(valueListenerClasses),
212206
ObjectUtils.nullSafeToString(listenerClasses));
213207
logger.error(msg);
@@ -220,16 +214,15 @@ else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
220214
if (listenerClasses != null) {
221215
classesList.addAll(0, Arrays.<Class<? extends TestExecutionListener>> asList(listenerClasses));
222216
}
223-
declaringClass = (testExecutionListeners.inheritListeners() ? AnnotationUtils.findAnnotationDeclaringClass(
224-
annotationType, declaringClass.getSuperclass())
225-
: null);
217+
declaringClass = (testExecutionListeners.inheritListeners() ?
218+
AnnotationUtils.findAnnotationDeclaringClass(annotationType, declaringClass.getSuperclass()) : null);
226219
}
227220
}
228221

229222
List<TestExecutionListener> listeners = new ArrayList<TestExecutionListener>(classesList.size());
230223
for (Class<? extends TestExecutionListener> listenerClass : classesList) {
231224
try {
232-
listeners.add((TestExecutionListener) BeanUtils.instantiateClass(listenerClass));
225+
listeners.add(BeanUtils.instantiateClass(listenerClass));
233226
}
234227
catch (NoClassDefFoundError err) {
235228
if (defaultListeners) {
@@ -252,11 +245,12 @@ else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
252245
*/
253246
@SuppressWarnings("unchecked")
254247
protected Set<Class<? extends TestExecutionListener>> getDefaultTestExecutionListenerClasses() {
255-
Set<Class<? extends TestExecutionListener>> defaultListenerClasses = new LinkedHashSet<Class<? extends TestExecutionListener>>();
248+
Set<Class<? extends TestExecutionListener>> defaultListenerClasses =
249+
new LinkedHashSet<Class<? extends TestExecutionListener>>();
256250
for (String className : DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES) {
257251
try {
258-
defaultListenerClasses.add((Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(
259-
className));
252+
defaultListenerClasses.add(
253+
(Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(className));
260254
}
261255
catch (Throwable ex) {
262256
if (logger.isDebugEnabled()) {
@@ -268,17 +262,16 @@ protected Set<Class<? extends TestExecutionListener>> getDefaultTestExecutionLis
268262
return defaultListenerClasses;
269263
}
270264

265+
271266
/**
272267
* Hook for pre-processing a test class <em>before</em> execution of any
273268
* tests within the class. Should be called prior to any framework-specific
274269
* <em>before class methods</em> (e.g., methods annotated with JUnit's
275270
* {@link org.junit.BeforeClass &#064;BeforeClass}).
276-
* <p>
277-
* An attempt will be made to give each registered
271+
* <p>An attempt will be made to give each registered
278272
* {@link TestExecutionListener} a chance to pre-process the test class
279273
* execution. If a listener throws an exception, however, the remaining
280274
* registered listeners will <strong>not</strong> be called.
281-
*
282275
* @throws Exception if a registered TestExecutionListener throws an
283276
* exception
284277
* @see #getTestExecutionListeners()
@@ -306,19 +299,14 @@ public void beforeTestClass() throws Exception {
306299
* Hook for preparing a test instance prior to execution of any individual
307300
* test methods, for example for injecting dependencies, etc. Should be
308301
* called immediately after instantiation of the test instance.
309-
* <p>
310-
* The managed {@link TestContext} will be updated with the supplied
302+
* <p>The managed {@link TestContext} will be updated with the supplied
311303
* <code>testInstance</code>.
312-
* <p>
313-
* An attempt will be made to give each registered
304+
* <p>An attempt will be made to give each registered
314305
* {@link TestExecutionListener} a chance to prepare the test instance. If a
315306
* listener throws an exception, however, the remaining registered listeners
316307
* will <strong>not</strong> be called.
317-
*
318-
* @param testInstance the test instance to prepare (never <code>null</code>
319-
* )
320-
* @throws Exception if a registered TestExecutionListener throws an
321-
* exception
308+
* @param testInstance the test instance to prepare (never <code>null</code>)
309+
* @throws Exception if a registered TestExecutionListener throws an exception
322310
* @see #getTestExecutionListeners()
323311
*/
324312
public void prepareTestInstance(Object testInstance) throws Exception {
@@ -346,20 +334,16 @@ public void prepareTestInstance(Object testInstance) throws Exception {
346334
* starting a transaction, etc. Should be called prior to any
347335
* framework-specific <em>before methods</em> (e.g., methods annotated with
348336
* JUnit's {@link org.junit.Before &#064;Before}).
349-
* <p>
350-
* The managed {@link TestContext} will be updated with the supplied
337+
* <p>The managed {@link TestContext} will be updated with the supplied
351338
* <code>testInstance</code> and <code>testMethod</code>.
352-
* <p>
353-
* An attempt will be made to give each registered
339+
* <p>An attempt will be made to give each registered
354340
* {@link TestExecutionListener} a chance to pre-process the test method
355341
* execution. If a listener throws an exception, however, the remaining
356342
* registered listeners will <strong>not</strong> be called.
357-
*
358343
* @param testInstance the current test instance (never <code>null</code>)
359344
* @param testMethod the test method which is about to be executed on the
360345
* test instance
361-
* @throws Exception if a registered TestExecutionListener throws an
362-
* exception
346+
* @throws Exception if a registered TestExecutionListener throws an exception
363347
* @see #getTestExecutionListeners()
364348
*/
365349
public void beforeTestMethod(Object testInstance, Method testMethod) throws Exception {
@@ -388,26 +372,22 @@ public void beforeTestMethod(Object testInstance, Method testMethod) throws Exce
388372
* ending a transaction, etc. Should be called after any framework-specific
389373
* <em>after methods</em> (e.g., methods annotated with JUnit's
390374
* {@link org.junit.After &#064;After}).
391-
* <p>
392-
* The managed {@link TestContext} will be updated with the supplied
375+
* <p>The managed {@link TestContext} will be updated with the supplied
393376
* <code>testInstance</code>, <code>testMethod</code>, and
394377
* <code>exception</code>.
395-
* <p>
396-
* Each registered {@link TestExecutionListener} will be given a chance to
378+
* <p>Each registered {@link TestExecutionListener} will be given a chance to
397379
* post-process the test method execution. If a listener throws an
398380
* exception, the remaining registered listeners will still be called, but
399381
* the first exception thrown will be tracked and rethrown after all
400382
* listeners have executed. Note that registered listeners will be executed
401383
* in the opposite order in which they were registered.
402-
*
403384
* @param testInstance the current test instance (never <code>null</code>)
404385
* @param testMethod the test method which has just been executed on the
405386
* test instance
406387
* @param exception the exception that was thrown during execution of the
407388
* test method or by a TestExecutionListener, or <code>null</code> if none
408389
* was thrown
409-
* @throws Exception if a registered TestExecutionListener throws an
410-
* exception
390+
* @throws Exception if a registered TestExecutionListener throws an exception
411391
* @see #getTestExecutionListeners()
412392
*/
413393
public void afterTestMethod(Object testInstance, Method testMethod, Throwable exception) throws Exception {
@@ -444,16 +424,13 @@ public void afterTestMethod(Object testInstance, Method testMethod, Throwable ex
444424
* tests within the class. Should be called after any framework-specific
445425
* <em>after class methods</em> (e.g., methods annotated with JUnit's
446426
* {@link org.junit.AfterClass &#064;AfterClass}).
447-
* <p>
448-
* Each registered {@link TestExecutionListener} will be given a chance to
427+
* <p>Each registered {@link TestExecutionListener} will be given a chance to
449428
* post-process the test class. If a listener throws an exception, the
450429
* remaining registered listeners will still be called, but the first
451430
* exception thrown will be tracked and rethrown after all listeners have
452431
* executed. Note that registered listeners will be executed in the opposite
453432
* order in which they were registered.
454-
*
455-
* @throws Exception if a registered TestExecutionListener throws an
456-
* exception
433+
* @throws Exception if a registered TestExecutionListener throws an exception
457434
* @see #getTestExecutionListeners()
458435
*/
459436
public void afterTestClass() throws Exception {

0 commit comments

Comments
 (0)