Skip to content

Commit 977179c

Browse files
author
Mateusz Pietryga
committed
LifecycleMethodExecutionExceptionHandler user guide and release notes
1 parent 39ea6d6 commit 977179c

File tree

5 files changed

+181
-13
lines changed

5 files changed

+181
-13
lines changed

documentation/src/docs/asciidoc/link-attributes.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ endif::[]
8181
:ExtensionContext: {javadoc-root}/org/junit/jupiter/api/extension/ExtensionContext.html[ExtensionContext]
8282
:ExtensionContext_Store: {javadoc-root}/org/junit/jupiter/api/extension/ExtensionContext.Store.html[Store]
8383
:InvocationInterceptor: {javadoc-root}/org/junit/jupiter/api/extension/InvocationInterceptor.html[InvocationInterceptor]
84+
:LifecycleMethodExecutionExceptionHandler: {javadoc-root}/org/junit/jupiter/api/extension/LifecycleMethodExecutionExceptionHandler.html[LifecycleMethodExecutionExceptionHandler]
8485
:ParameterResolver: {javadoc-root}/org/junit/jupiter/api/extension/ParameterResolver.html[ParameterResolver]
8586
:RegisterExtension: {javadoc-root}/org/junit/jupiter/api/extension/RegisterExtension.html[@RegisterExtension]
8687
:TestExecutionExceptionHandler: {javadoc-root}/org/junit/jupiter/api/extension/TestExecutionExceptionHandler.html[TestExecutionExceptionHandler]

documentation/src/docs/asciidoc/release-notes/release-notes-5.5.0-RC1.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ on GitHub.
7777
* New `junit.jupiter.displayname.generator.default` configuration parameter to set the
7878
default `DisplayNameGenerator` that will be used unless `@DisplayName` or
7979
`@DisplayNameGeneration` is present.
80+
details)
81+
* New extension APIs for handling exceptions during execution of lifecycle methods:
82+
`@BeforeAll`, `@BeforeEach`, `@AfterEach` and `@AfterAll` (see
83+
<<../user-guide/index.adoc#extensions-exception-handling, User Guide>> for
84+
details)
8085

8186

8287
[[release-notes-5.5.0-RC1-junit-vintage]]

documentation/src/docs/asciidoc/user-guide/extensions.adoc

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -433,18 +433,51 @@ INFO: Method [sleep50ms] took 53 ms.
433433
[[extensions-exception-handling]]
434434
=== Exception Handling
435435

436-
`{TestExecutionExceptionHandler}` defines the API for `Extensions` that wish to handle
437-
exceptions thrown during test execution.
436+
Exceptions thrown during the test execution may be intercepted and handled accordingly
437+
before propagating further, so that certain actions like error logging or resource releasing
438+
may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that
439+
wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}`
440+
and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`,
441+
`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`
438442

439443
The following example shows an extension which will swallow all instances of `IOException`
440444
but rethrow any other type of exception.
441445

442446
[source,java,indent=0]
443-
.An exception handling extension
447+
.An exception handling extension that filters IOExceptions in test execution
444448
----
445449
include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide]
446450
----
447451

452+
Another example shows how to record the state of an application under test exactly at
453+
the point of unexpected exception being thrown during setup and cleanup. Note that unlike
454+
relying on lifecycle callbacks, which may or may not be executed depending on the test
455+
status, this solution guarantees execution immediately after failing `@BeforeAll`,
456+
`@BeforeEach`, `@AfterEach` or `@AfterAll`.
457+
458+
[source,java,indent=0]
459+
.An exception handling extension that records application state on error
460+
----
461+
include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide]
462+
----
463+
464+
Multiple execution exception handlers may be invoked for the same lifecycle method in
465+
order of declaration. If one of the handlers swallows the handled exception, subsequent
466+
ones will not be executed, and no failure will be propagated to JUnit engine, as if the
467+
exception was never thrown. Handlers may also choose to rethrow the exception or throw
468+
a different one, potentially wrapping the original.
469+
470+
Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle
471+
exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level,
472+
while handlers for `BeforeEach` and `AfterEach` may be also registered for individual
473+
test methods.
474+
475+
[source,java,indent=0]
476+
.An exception handling extension that records application state on error
477+
----
478+
include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide]
479+
----
480+
448481
[[extensions-intercepting-invocations]]
449482
=== Intercepting Invocations
450483

@@ -584,7 +617,7 @@ test method and will be repeated for every test method in the test class.
584617
[#extensions-execution-order-diagram,reftext='{figure-caption}']
585618
image::extensions_lifecycle.png[caption='',title='{figure-caption}']
586619

587-
The following table further explains the twelve steps in the
620+
The following table further explains the sixteen steps in the
588621
<<extensions-execution-order-diagram>> diagram.
589622

590623
[cols="5,15,80"]
@@ -600,42 +633,58 @@ The following table further explains the twelve steps in the
600633
| user code executed before all tests of the container are executed
601634

602635
| 3
636+
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler`
637+
| extension code for handling exceptions thrown during a method annotated with `@BeforeAll`
638+
639+
| 4
603640
| interface `org.junit.jupiter.api.extension.BeforeEachCallback`
604641
| extension code executed before each test is executed
605642

606-
| 4
643+
| 5
607644
| annotation `org.junit.jupiter.api.BeforeEach`
608645
| user code executed before each test is executed
609646

610-
| 5
647+
| 6
648+
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler`
649+
| extension code for handling exceptions thrown during a method annotated with `@BeforeEach`
650+
651+
| 7
611652
| interface `org.junit.jupiter.api.extension.BeforeTestExecutionCallback`
612653
| extension code executed immediately before a test is executed
613654

614-
| 6
655+
| 8
615656
| annotation `org.junit.jupiter.api.Test`
616657
| user code of the actual test method
617658

618-
| 7
659+
| 9
619660
| interface `org.junit.jupiter.api.extension.TestExecutionExceptionHandler`
620661
| extension code for handling exceptions thrown during a test
621662

622-
| 8
663+
| 10
623664
| interface `org.junit.jupiter.api.extension.AfterTestExecutionCallback`
624665
| extension code executed immediately after test execution and its corresponding exception handlers
625666

626-
| 9
667+
| 11
627668
| annotation `org.junit.jupiter.api.AfterEach`
628669
| user code executed after each test is executed
629670

630-
| 10
671+
| 12
672+
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler`
673+
| extension code for handling exceptions thrown during a method annotated with `@AfterEach`
674+
675+
| 13
631676
| interface `org.junit.jupiter.api.extension.AfterEachCallback`
632677
| extension code executed after each test is executed
633678

634-
| 11
679+
| 14
635680
| annotation `org.junit.jupiter.api.AfterAll`
636681
| user code executed after all tests of the container are executed
637682

638-
| 12
683+
| 15
684+
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler`
685+
| extension code for handling exceptions thrown during a method annotated with `@AfterAll`
686+
687+
| 16
639688
| interface `org.junit.jupiter.api.extension.AfterAllCallback`
640689
| extension code executed after all tests of the container are executed
641690

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2015-2019 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package example.exception;
12+
13+
import static example.exception.MultipleHandlersTestCase.ThirdExecutedHandler;
14+
15+
import org.junit.jupiter.api.Test;
16+
import org.junit.jupiter.api.extension.ExtendWith;
17+
import org.junit.jupiter.api.extension.ExtensionContext;
18+
import org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler;
19+
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
20+
21+
// @formatter:off
22+
// tag::user_guide[]
23+
// Register handlers for @Test, @BeforeEach, @AfterEach as well as @BeforeAll and @AfterAll
24+
@ExtendWith({ThirdExecutedHandler.class})
25+
class MultipleHandlersTestCase {
26+
27+
// Register handlers for @Test, @BeforeEach, @AfterEach only
28+
@ExtendWith(SecondExecutedHandler.class)
29+
@ExtendWith(FirstExecutedHandler.class)
30+
@Test
31+
void testMethod() {
32+
}
33+
34+
// end::user_guide[]
35+
36+
static class FirstExecutedHandler implements TestExecutionExceptionHandler {
37+
@Override
38+
public void handleTestExecutionException(ExtensionContext context, Throwable ex)
39+
throws Throwable {
40+
throw ex;
41+
}
42+
}
43+
44+
static class SecondExecutedHandler implements LifecycleMethodExecutionExceptionHandler {
45+
@Override
46+
public void handleBeforeEachMethodExecutionException(ExtensionContext context, Throwable ex)
47+
throws Throwable {
48+
throw ex;
49+
}
50+
}
51+
52+
static class ThirdExecutedHandler implements LifecycleMethodExecutionExceptionHandler {
53+
@Override
54+
public void handleBeforeAllMethodExecutionException(ExtensionContext context, Throwable ex)
55+
throws Throwable {
56+
throw ex;
57+
}
58+
}
59+
}
60+
// @formatter:on
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2015-2019 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package example.exception;
12+
13+
import org.junit.jupiter.api.extension.ExtensionContext;
14+
import org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler;
15+
16+
// @formatter:off
17+
// tag::user_guide[]
18+
class RecordStateOnErrorExtension implements LifecycleMethodExecutionExceptionHandler {
19+
20+
@Override
21+
public void handleBeforeAllMethodExecutionException(ExtensionContext context, Throwable ex)
22+
throws Throwable {
23+
memoryDumpForFurtherInvestigation("Failure recorded during class setup");
24+
throw ex;
25+
}
26+
27+
@Override
28+
public void handleBeforeEachMethodExecutionException(ExtensionContext context, Throwable ex)
29+
throws Throwable {
30+
memoryDumpForFurtherInvestigation("Failure recorded during test setup");
31+
throw ex;
32+
}
33+
34+
@Override
35+
public void handleAfterEachMethodExecutionException(ExtensionContext context, Throwable ex)
36+
throws Throwable {
37+
memoryDumpForFurtherInvestigation("Failure recorded during test cleanup");
38+
throw ex;
39+
}
40+
41+
@Override
42+
public void handleAfterAllMethodExecutionException(ExtensionContext context, Throwable ex)
43+
throws Throwable {
44+
memoryDumpForFurtherInvestigation("Failure recorded during class cleanup");
45+
throw ex;
46+
}
47+
// end::user_guide[]
48+
49+
private void memoryDumpForFurtherInvestigation(String error) {
50+
51+
}
52+
}
53+
// @formatter:on

0 commit comments

Comments
 (0)