40
40
* <li>{@link #beforeTestClass() before test class execution}: prior to any
41
41
* <em>before class callbacks</em> of a particular testing framework (e.g.,
42
42
* JUnit 4's {@link org.junit.BeforeClass @BeforeClass})</li>
43
- * <li>{@link #prepareTestInstance(Object) test instance preparation}:
44
- * immediately following instantiation of the test instance </li>
45
- * <li>{@link #beforeTestMethod(Object, Method) before test method execution }:
43
+ * <li>{@link #prepareTestInstance test instance preparation}:
44
+ * immediately following instantiation of the test class </li>
45
+ * <li>{@link #beforeTestMethod before test setup }:
46
46
* prior to any <em>before method callbacks</em> of a particular testing framework
47
47
* (e.g., JUnit 4's {@link org.junit.Before @Before})</li>
48
- * <li>{@link #afterTestMethod(Object, Method, Throwable) after test method
49
- * execution}: after any <em>after method callbacks</em> of a particular testing
48
+ * <li>{@link #beforeTestExecution before test execution}:
49
+ * immediately before execution of the {@linkplain java.lang.reflect.Method
50
+ * test method} but after test setup</li>
51
+ * <li>{@link #afterTestExecution after test execution}:
52
+ * immediately after execution of the {@linkplain java.lang.reflect.Method
53
+ * test method} but before test tear down</li>
54
+ * <li>{@link #afterTestMethod(Object, Method, Throwable) after test tear down}:
55
+ * after any <em>after method callbacks</em> of a particular testing
50
56
* framework (e.g., JUnit 4's {@link org.junit.After @After})</li>
51
57
* <li>{@link #afterTestClass() after test class execution}: after any
52
- * <em>after class callbacks</em> of a particular testing framework (e.g., JUnit
53
- * 4's {@link org.junit.AfterClass @AfterClass})</li>
58
+ * <em>after class callbacks</em> of a particular testing framework (e.g., JUnit 4's
59
+ * {@link org.junit.AfterClass @AfterClass})</li>
54
60
* </ul>
55
61
*
56
62
* <p>Support for loading and accessing
57
- * {@link org.springframework.context.ApplicationContext application contexts},
63
+ * {@linkplain org.springframework.context.ApplicationContext application contexts},
58
64
* dependency injection of test instances,
59
- * {@link org.springframework.transaction.annotation.Transactional transactional}
65
+ * {@linkplain org.springframework.transaction.annotation.Transactional transactional}
60
66
* execution of test methods, etc. is provided by
61
67
* {@link SmartContextLoader ContextLoaders} and {@link TestExecutionListener
62
68
* TestExecutionListeners}, which are configured via
@@ -173,14 +179,15 @@ private List<TestExecutionListener> getReversedTestExecutionListeners() {
173
179
/**
174
180
* Hook for pre-processing a test class <em>before</em> execution of any
175
181
* tests within the class. Should be called prior to any framework-specific
176
- * <em>before class methods</em> (e.g., methods annotated with JUnit's
182
+ * <em>before class methods</em> (e.g., methods annotated with JUnit 4 's
177
183
* {@link org.junit.BeforeClass @BeforeClass}).
178
184
* <p>An attempt will be made to give each registered
179
185
* {@link TestExecutionListener} a chance to pre-process the test class
180
186
* execution. If a listener throws an exception, however, the remaining
181
187
* registered listeners will <strong>not</strong> be called.
182
188
* @throws Exception if a registered TestExecutionListener throws an
183
189
* exception
190
+ * @since 3.0
184
191
* @see #getTestExecutionListeners()
185
192
*/
186
193
public void beforeTestClass () throws Exception {
@@ -195,10 +202,7 @@ public void beforeTestClass() throws Exception {
195
202
testExecutionListener .beforeTestClass (getTestContext ());
196
203
}
197
204
catch (Throwable ex ) {
198
- if (logger .isWarnEnabled ()) {
199
- logger .warn ("Caught exception while allowing TestExecutionListener [" + testExecutionListener +
200
- "] to process 'before class' callback for test class [" + testClass + "]" , ex );
201
- }
205
+ logException (ex , "beforeTestClass" , testExecutionListener , testClass );
202
206
ReflectionUtils .rethrowException (ex );
203
207
}
204
208
}
@@ -240,76 +244,172 @@ public void prepareTestInstance(Object testInstance) throws Exception {
240
244
}
241
245
242
246
/**
243
- * Hook for pre-processing a test <em>before</em> execution of the supplied
244
- * {@link Method test method}, for example for setting up test fixtures,
245
- * starting a transaction, etc. Should be called prior to any
246
- * framework-specific <em>before methods</em> (e.g., methods annotated with
247
- * JUnit's {@link org.junit.Before @Before}).
247
+ * Hook for pre-processing a test <em>before</em> execution of <em>before</em>
248
+ * lifecycle callbacks of the underlying test framework — for example,
249
+ * setting up test fixtures, starting a transaction, etc.
250
+ * <p>This method <strong>must</strong> be called immediately prior to
251
+ * framework-specific <em>before</em> lifecycle callbacks (e.g., methods
252
+ * annotated with JUnit 4's {@link org.junit.Before @Before}). For historical
253
+ * reasons, this method is named {@code beforeTestMethod}. Since the
254
+ * introduction of {@link #beforeTestExecution}, a more suitable name for
255
+ * this method might be something like {@code beforeTestSetUp} or
256
+ * {@code beforeEach}; however, it is unfortunately impossible to rename
257
+ * this method due to backward compatibility concerns.
248
258
* <p>The managed {@link TestContext} will be updated with the supplied
249
259
* {@code testInstance} and {@code testMethod}.
250
260
* <p>An attempt will be made to give each registered
251
- * {@link TestExecutionListener} a chance to pre-process the test method
252
- * execution. If a listener throws an exception, however, the remaining
253
- * registered listeners will <strong>not</strong> be called.
261
+ * {@link TestExecutionListener} a chance to perform its pre-processing.
262
+ * If a listener throws an exception, however, the remaining registered
263
+ * listeners will <strong>not</strong> be called.
254
264
* @param testInstance the current test instance (never {@code null})
255
265
* @param testMethod the test method which is about to be executed on the
256
266
* test instance
257
267
* @throws Exception if a registered TestExecutionListener throws an exception
268
+ * @see #afterTestMethod
269
+ * @see #beforeTestExecution
270
+ * @see #afterTestExecution
258
271
* @see #getTestExecutionListeners()
259
272
*/
260
273
public void beforeTestMethod (Object testInstance , Method testMethod ) throws Exception {
261
- Assert .notNull (testInstance , "Test instance must not be null" );
262
- if (logger .isTraceEnabled ()) {
263
- logger .trace ("beforeTestMethod(): instance [" + testInstance + "], method [" + testMethod + "]" );
264
- }
265
- getTestContext ().updateState (testInstance , testMethod , null );
274
+ String callbackName = "beforeTestMethod" ;
275
+ prepareForBeforeCallback (callbackName , testInstance , testMethod );
266
276
267
277
for (TestExecutionListener testExecutionListener : getTestExecutionListeners ()) {
268
278
try {
269
279
testExecutionListener .beforeTestMethod (getTestContext ());
270
280
}
271
281
catch (Throwable ex ) {
272
- if (logger .isWarnEnabled ()) {
273
- logger .warn ("Caught exception while allowing TestExecutionListener [" + testExecutionListener +
274
- "] to process 'before' execution of test method [" + testMethod + "] for test instance [" +
275
- testInstance + "]" , ex );
276
- }
277
- ReflectionUtils .rethrowException (ex );
282
+ handleBeforeException (ex , callbackName , testExecutionListener , testInstance , testMethod );
283
+ }
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Hook for pre-processing a test <em>immediately before</em> execution of
289
+ * the {@linkplain java.lang.reflect.Method test method} in the supplied
290
+ * {@linkplain TestContext test context} — for example, for timing
291
+ * or logging purposes.
292
+ * <p>This method <strong>must</strong> be called after framework-specific
293
+ * <em>before</em> lifecycle callbacks (e.g., methods annotated with JUnit 4's
294
+ * {@link org.junit.Before @Before}).
295
+ * <p>The managed {@link TestContext} will be updated with the supplied
296
+ * {@code testInstance} and {@code testMethod}.
297
+ * <p>An attempt will be made to give each registered
298
+ * {@link TestExecutionListener} a chance to perform its pre-processing.
299
+ * If a listener throws an exception, however, the remaining registered
300
+ * listeners will <strong>not</strong> be called.
301
+ * @param testInstance the current test instance (never {@code null})
302
+ * @param testMethod the test method which is about to be executed on the
303
+ * test instance
304
+ * @throws Exception if a registered TestExecutionListener throws an exception
305
+ * @since 5.0
306
+ * @see #beforeTestMethod
307
+ * @see #afterTestMethod
308
+ * @see #beforeTestExecution
309
+ * @see #afterTestExecution
310
+ * @see #getTestExecutionListeners()
311
+ */
312
+ public void beforeTestExecution (Object testInstance , Method testMethod ) throws Exception {
313
+ String callbackName = "beforeTestExecution" ;
314
+ prepareForBeforeCallback (callbackName , testInstance , testMethod );
315
+
316
+ for (TestExecutionListener testExecutionListener : getTestExecutionListeners ()) {
317
+ try {
318
+ testExecutionListener .beforeTestExecution (getTestContext ());
319
+ }
320
+ catch (Throwable ex ) {
321
+ handleBeforeException (ex , callbackName , testExecutionListener , testInstance , testMethod );
278
322
}
279
323
}
280
324
}
281
325
282
326
/**
283
- * Hook for post-processing a test <em>after</em> execution of the supplied
284
- * {@link Method test method}, for example for tearing down test fixtures,
285
- * ending a transaction, etc. Should be called after any framework-specific
286
- * <em>after methods</em> (e.g., methods annotated with JUnit's
327
+ * Hook for post-processing a test <em>immediately after</em> execution of
328
+ * the {@linkplain java.lang.reflect.Method test method} in the supplied
329
+ * {@linkplain TestContext test context} — for example, for timing
330
+ * or logging purposes.
331
+ * <p>This method <strong>must</strong> be called before framework-specific
332
+ * <em>after</em> lifecycle callbacks (e.g., methods annotated with JUnit 4's
287
333
* {@link org.junit.After @After}).
288
334
* <p>The managed {@link TestContext} will be updated with the supplied
289
- * {@code testInstance}, {@code testMethod}, and
290
- * {@code exception}.
291
- * <p>Each registered {@link TestExecutionListener} will be given a chance to
292
- * post-process the test method execution. If a listener throws an
293
- * exception, the remaining registered listeners will still be called, but
294
- * the first exception thrown will be tracked and rethrown after all
295
- * listeners have executed. Note that registered listeners will be executed
296
- * in the opposite order in which they were registered.
335
+ * {@code testInstance}, {@code testMethod}, and {@code exception}.
336
+ * <p>Each registered {@link TestExecutionListener} will be given a chance
337
+ * to perform its post-processing. If a listener throws an exception, the
338
+ * remaining registered listeners will still be called, but the first
339
+ * exception thrown will be tracked and rethrown after all listeners have
340
+ * executed. Note that registered listeners will be executed in the opposite
341
+ * order in which they were registered.
297
342
* @param testInstance the current test instance (never {@code null})
298
343
* @param testMethod the test method which has just been executed on the
299
344
* test instance
300
345
* @param exception the exception that was thrown during execution of the
301
346
* test method or by a TestExecutionListener, or {@code null} if none
302
347
* was thrown
303
348
* @throws Exception if a registered TestExecutionListener throws an exception
349
+ * @since 5.0
350
+ * @see #beforeTestMethod
351
+ * @see #afterTestMethod
352
+ * @see #beforeTestExecution
304
353
* @see #getTestExecutionListeners()
305
354
*/
306
- public void afterTestMethod (Object testInstance , Method testMethod , Throwable exception ) throws Exception {
307
- Assert .notNull (testInstance , "Test instance must not be null" );
308
- if (logger .isTraceEnabled ()) {
309
- logger .trace ("afterTestMethod(): instance [" + testInstance + "], method [" + testMethod +
310
- "], exception [" + exception + "]" );
355
+ public void afterTestExecution (Object testInstance , Method testMethod , Throwable exception ) throws Exception {
356
+ String callbackName = "afterTestExecution" ;
357
+ prepareForAfterCallback (callbackName , testInstance , testMethod , exception );
358
+
359
+ Throwable afterTestExecutionException = null ;
360
+ // Traverse the TestExecutionListeners in reverse order to ensure proper
361
+ // "wrapper"-style execution of listeners.
362
+ for (TestExecutionListener testExecutionListener : getReversedTestExecutionListeners ()) {
363
+ try {
364
+ testExecutionListener .afterTestExecution (getTestContext ());
365
+ }
366
+ catch (Throwable ex ) {
367
+ logException (ex , callbackName , testExecutionListener , testInstance , testMethod );
368
+ if (afterTestExecutionException == null ) {
369
+ afterTestExecutionException = ex ;
370
+ }
371
+ }
311
372
}
312
- getTestContext ().updateState (testInstance , testMethod , exception );
373
+ if (afterTestExecutionException != null ) {
374
+ ReflectionUtils .rethrowException (afterTestExecutionException );
375
+ }
376
+ }
377
+
378
+ /**
379
+ * Hook for post-processing a test <em>after</em> execution of <em>after</em>
380
+ * lifecycle callbacks of the underlying test framework — for example,
381
+ * tearing down test fixtures, ending a transaction, etc.
382
+ * <p>This method <strong>must</strong> be called immediately after
383
+ * framework-specific <em>after</em> lifecycle callbacks (e.g., methods
384
+ * annotated with JUnit 4's {@link org.junit.After @After}). For historical
385
+ * reasons, this method is named {@code afterTestMethod}. Since the
386
+ * introduction of {@link #afterTestExecution}, a more suitable name for
387
+ * this method might be something like {@code afterTestTearDown} or
388
+ * {@code afterEach}; however, it is unfortunately impossible to rename
389
+ * this method due to backward compatibility concerns.
390
+ * <p>The managed {@link TestContext} will be updated with the supplied
391
+ * {@code testInstance}, {@code testMethod}, and {@code exception}.
392
+ * <p>Each registered {@link TestExecutionListener} will be given a chance
393
+ * to perform its post-processing. If a listener throws an exception, the
394
+ * remaining registered listeners will still be called, but the first
395
+ * exception thrown will be tracked and rethrown after all listeners have
396
+ * executed. Note that registered listeners will be executed in the opposite
397
+ * order in which they were registered.
398
+ * @param testInstance the current test instance (never {@code null})
399
+ * @param testMethod the test method which has just been executed on the
400
+ * test instance
401
+ * @param exception the exception that was thrown during execution of the
402
+ * test method or by a TestExecutionListener, or {@code null} if none
403
+ * was thrown
404
+ * @throws Exception if a registered TestExecutionListener throws an exception
405
+ * @see #beforeTestMethod
406
+ * @see #beforeTestExecution
407
+ * @see #afterTestExecution
408
+ * @see #getTestExecutionListeners()
409
+ */
410
+ public void afterTestMethod (Object testInstance , Method testMethod , Throwable exception ) throws Exception {
411
+ String callbackName = "afterTestMethod" ;
412
+ prepareForAfterCallback (callbackName , testInstance , testMethod , exception );
313
413
314
414
Throwable afterTestMethodException = null ;
315
415
// Traverse the TestExecutionListeners in reverse order to ensure proper
@@ -319,11 +419,7 @@ public void afterTestMethod(Object testInstance, Method testMethod, Throwable ex
319
419
testExecutionListener .afterTestMethod (getTestContext ());
320
420
}
321
421
catch (Throwable ex ) {
322
- if (logger .isWarnEnabled ()) {
323
- logger .warn ("Caught exception while allowing TestExecutionListener [" + testExecutionListener +
324
- "] to process 'after' execution for test: method [" + testMethod + "], instance [" +
325
- testInstance + "], exception [" + exception + "]" , ex );
326
- }
422
+ logException (ex , callbackName , testExecutionListener , testInstance , testMethod );
327
423
if (afterTestMethodException == null ) {
328
424
afterTestMethodException = ex ;
329
425
}
@@ -337,7 +433,7 @@ public void afterTestMethod(Object testInstance, Method testMethod, Throwable ex
337
433
/**
338
434
* Hook for post-processing a test class <em>after</em> execution of all
339
435
* tests within the class. Should be called after any framework-specific
340
- * <em>after class methods</em> (e.g., methods annotated with JUnit's
436
+ * <em>after class methods</em> (e.g., methods annotated with JUnit 4 's
341
437
* {@link org.junit.AfterClass @AfterClass}).
342
438
* <p>Each registered {@link TestExecutionListener} will be given a chance to
343
439
* post-process the test class. If a listener throws an exception, the
@@ -346,6 +442,7 @@ public void afterTestMethod(Object testInstance, Method testMethod, Throwable ex
346
442
* executed. Note that registered listeners will be executed in the opposite
347
443
* order in which they were registered.
348
444
* @throws Exception if a registered TestExecutionListener throws an exception
445
+ * @since 3.0
349
446
* @see #getTestExecutionListeners()
350
447
*/
351
448
public void afterTestClass () throws Exception {
@@ -363,10 +460,7 @@ public void afterTestClass() throws Exception {
363
460
testExecutionListener .afterTestClass (getTestContext ());
364
461
}
365
462
catch (Throwable ex ) {
366
- if (logger .isWarnEnabled ()) {
367
- logger .warn ("Caught exception while allowing TestExecutionListener [" + testExecutionListener +
368
- "] to process 'after class' callback for test class [" + testClass + "]" , ex );
369
- }
463
+ logException (ex , "afterTestClass" , testExecutionListener , testClass );
370
464
if (afterTestClassException == null ) {
371
465
afterTestClassException = ex ;
372
466
}
@@ -377,4 +471,46 @@ public void afterTestClass() throws Exception {
377
471
}
378
472
}
379
473
474
+ private void prepareForBeforeCallback (String callbackName , Object testInstance , Method testMethod ) {
475
+ Assert .notNull (testInstance , "Test instance must not be null" );
476
+ if (logger .isTraceEnabled ()) {
477
+ logger .trace (String .format ("%s(): instance [%s], method [%s]" , callbackName , testInstance , testMethod ));
478
+ }
479
+ getTestContext ().updateState (testInstance , testMethod , null );
480
+ }
481
+
482
+ private void prepareForAfterCallback (String callbackName , Object testInstance , Method testMethod ,
483
+ Throwable exception ) {
484
+ Assert .notNull (testInstance , "Test instance must not be null" );
485
+ if (logger .isTraceEnabled ()) {
486
+ logger .trace (String .format ("%s(): instance [%s], method [%s], exception [%s]" , callbackName , testInstance ,
487
+ testMethod , exception ));
488
+ }
489
+ getTestContext ().updateState (testInstance , testMethod , exception );
490
+ }
491
+
492
+ private void handleBeforeException (Throwable ex , String callbackName , TestExecutionListener testExecutionListener ,
493
+ Object testInstance , Method testMethod ) throws Exception {
494
+ logException (ex , callbackName , testExecutionListener , testInstance , testMethod );
495
+ ReflectionUtils .rethrowException (ex );
496
+ }
497
+
498
+ private void logException (Throwable ex , String callbackName , TestExecutionListener testExecutionListener ,
499
+ Class <?> testClass ) {
500
+ if (logger .isWarnEnabled ()) {
501
+ logger .warn (String .format ("Caught exception while invoking '%s' callback on " +
502
+ "TestExecutionListener [%s] for test class [%s]" , callbackName , testExecutionListener ,
503
+ testClass ), ex );
504
+ }
505
+ }
506
+
507
+ private void logException (Throwable ex , String callbackName , TestExecutionListener testExecutionListener ,
508
+ Object testInstance , Method testMethod ) {
509
+ if (logger .isWarnEnabled ()) {
510
+ logger .warn (String .format ("Caught exception while invoking '%s' callback on " +
511
+ "TestExecutionListener [%s] for test method [%s] and test instance [%s]" ,
512
+ callbackName , testExecutionListener , testMethod , testInstance ), ex );
513
+ }
514
+ }
515
+
380
516
}
0 commit comments