Skip to content

Commit 517b9c0

Browse files
authored
Introduce per-invocation lifecycle callbacks for container templates (#4353)
Resolves #4320.
1 parent 0068c24 commit 517b9c0

23 files changed

+595
-220
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,12 @@ endif::[]
137137
// Jupiter Extension APIs
138138
:extension-api-package: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/package-summary.html[org.junit.jupiter.api.extension]
139139
:AfterAllCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterAllCallback.html[AfterAllCallback]
140+
:AfterContainerTemplateInvocationCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterContainerTemplateInvocationCallback.html[AfterContainerTemplateInvocationCallback]
140141
:AfterEachCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterEachCallback.html[AfterEachCallback]
141142
:AfterTestExecutionCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterTestExecutionCallback.html[AfterTestExecutionCallback]
142143
:ParameterContext: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ParameterContext.html[ParameterContext]
143144
:BeforeAllCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeAllCallback.html[BeforeAllCallback]
145+
:BeforeContainerTemplateInvocationCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeContainerTemplateInvocationCallback.html[BeforeContainerTemplateInvocationCallback]
144146
:BeforeEachCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeEachCallback.html[BeforeEachCallback]
145147
:BeforeTestExecutionCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeTestExecutionCallback.html[BeforeTestExecutionCallback]
146148
:ContainerTemplateInvocationContext: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ContainerTemplateInvocationContext.html[ContainerTemplateInvocationContext]

documentation/src/docs/asciidoc/release-notes/release-notes-5.13.0-M1.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ repository on GitHub.
6868
updated documentation in the
6969
<<../user-guide/index.adoc#writing-tests-display-name-generator, User Guide>> for an
7070
example.
71+
* New `BeforeContainerTemplateInvocationCallback` and
72+
`AfterContainerTemplateInvocationCallback` extension callback interfaces allow
73+
implementing extensions that are invoked before and after each invocation of a container
74+
template.
7175
* New `TestTemplateInvocationContext.prepareInvocation(ExtensionContext)` callback method
7276
which allows extensions to prepare the `ExtensionContext` before the test template
7377
method is invoked. This may be used, for example, to store entries in the

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

Lines changed: 51 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -636,10 +636,14 @@ test execution lifecycle. Consult the following sections for examples and the Ja
636636
each of these interfaces in the `{extension-api-package}` package for further details.
637637

638638
* `{BeforeAllCallback}`
639-
** `{BeforeEachCallback}`
640-
*** `{BeforeTestExecutionCallback}`
641-
*** `{AfterTestExecutionCallback}`
642-
** `{AfterEachCallback}`
639+
** `{BeforeContainerTemplateInvocationCallback}` (only applicable for
640+
<<writing-tests-container-templates, container templates>>)
641+
*** `{BeforeEachCallback}`
642+
**** `{BeforeTestExecutionCallback}`
643+
**** `{AfterTestExecutionCallback}`
644+
*** `{AfterEachCallback}`
645+
** `{AfterContainerTemplateInvocationCallback}` (only applicable for
646+
<<writing-tests-container-templates, container templates>>)
643647
* `{AfterAllCallback}`
644648

645649
.Implementing Multiple Extension APIs
@@ -1010,81 +1014,48 @@ image::extensions_lifecycle.png[caption='',title='{figure-caption}']
10101014
The following table further explains the sixteen steps in the
10111015
<<extensions-execution-order-diagram>> diagram.
10121016

1013-
[cols="5,15,80"]
1014-
|===
1015-
| Step | Interface/Annotation | Description
1016-
1017-
| 1
1018-
| interface `org.junit.jupiter.api.extension.BeforeAllCallback`
1019-
| extension code executed before all tests of the container are executed
1020-
1021-
| 2
1022-
| annotation `org.junit.jupiter.api.BeforeAll`
1023-
| user code executed before all tests of the container are executed
1024-
1025-
| 3
1026-
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler
1027-
#handleBeforeAllMethodExecutionException`
1028-
| extension code for handling exceptions thrown from `@BeforeAll` methods
1029-
1030-
| 4
1031-
| interface `org.junit.jupiter.api.extension.BeforeEachCallback`
1032-
| extension code executed before each test is executed
1033-
1034-
| 5
1035-
| annotation `org.junit.jupiter.api.BeforeEach`
1036-
| user code executed before each test is executed
1037-
1038-
| 6
1039-
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler
1040-
#handleBeforeEachMethodExecutionException`
1041-
| extension code for handling exceptions thrown from `@BeforeEach` methods
1042-
1043-
| 7
1044-
| interface `org.junit.jupiter.api.extension.BeforeTestExecutionCallback`
1045-
| extension code executed immediately before a test is executed
1046-
1047-
| 8
1048-
| annotation `org.junit.jupiter.api.Test`
1049-
| user code of the actual test method
1050-
1051-
| 9
1052-
| interface `org.junit.jupiter.api.extension.TestExecutionExceptionHandler`
1053-
| extension code for handling exceptions thrown during a test
1054-
1055-
| 10
1056-
| interface `org.junit.jupiter.api.extension.AfterTestExecutionCallback`
1057-
| extension code executed immediately after test execution and its corresponding exception handlers
1058-
1059-
| 11
1060-
| annotation `org.junit.jupiter.api.AfterEach`
1061-
| user code executed after each test is executed
1062-
1063-
| 12
1064-
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler
1065-
#handleAfterEachMethodExecutionException`
1066-
| extension code for handling exceptions thrown from `@AfterEach` methods
1067-
1068-
| 13
1069-
| interface `org.junit.jupiter.api.extension.AfterEachCallback`
1070-
| extension code executed after each test is executed
1071-
1072-
| 14
1073-
| annotation `org.junit.jupiter.api.AfterAll`
1074-
| user code executed after all tests of the container are executed
1075-
1076-
| 15
1077-
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler
1078-
#handleAfterAllMethodExecutionException`
1079-
| extension code for handling exceptions thrown from `@AfterAll` methods
1080-
1081-
| 16
1082-
| interface `org.junit.jupiter.api.extension.AfterAllCallback`
1083-
| extension code executed after all tests of the container are executed
1084-
1085-
|===
1086-
1087-
In the simplest case only the actual test method will be executed (step 8); all other
1017+
. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` +
1018+
extension code executed before all tests of the container are executed
1019+
. *annotation* `*org.junit.jupiter.api.BeforeAll*` +
1020+
user code executed before all tests of the container are executed
1021+
. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler
1022+
#handleBeforeAllMethodExecutionException*` +
1023+
extension code for handling exceptions thrown from `@BeforeAll` methods
1024+
. *interface* `*org.junit.jupiter.api.extension.BeforeContainerTemplateInvocationCallback*` +
1025+
extension code executed before each container template invocation is executed (only applicable if the test class is a <<writing-tests-container-templates, container template>>)
1026+
. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` +
1027+
extension code executed before each test is executed
1028+
. *annotation* `*org.junit.jupiter.api.BeforeEach*` +
1029+
user code executed before each test is executed
1030+
. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler
1031+
#handleBeforeEachMethodExecutionException*` +
1032+
extension code for handling exceptions thrown from `@BeforeEach` methods
1033+
. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` +
1034+
extension code executed immediately before a test is executed
1035+
. *annotation* `*org.junit.jupiter.api.Test*` +
1036+
user code of the actual test method
1037+
. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` +
1038+
extension code for handling exceptions thrown during a test
1039+
. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` +
1040+
extension code executed immediately after test execution and its corresponding exception handlers
1041+
. *annotation* `*org.junit.jupiter.api.AfterEach*` +
1042+
user code executed after each test is executed
1043+
. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler
1044+
#handleAfterEachMethodExecutionException*` +
1045+
extension code for handling exceptions thrown from `@AfterEach` methods
1046+
. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` +
1047+
extension code executed after each test is executed
1048+
. *interface* `*org.junit.jupiter.api.extension.AfterContainerTemplateInvocationCallback*` +
1049+
extension code executed after each container template invocation is executed (only applicable if the test class is a <<writing-tests-container-templates, container template>>)
1050+
. *annotation* `*org.junit.jupiter.api.AfterAll*` +
1051+
user code executed after all tests of the container are executed
1052+
. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler
1053+
#handleAfterAllMethodExecutionException*` +
1054+
extension code for handling exceptions thrown from `@AfterAll` methods
1055+
. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` +
1056+
extension code executed after all tests of the container are executed
1057+
1058+
In the simplest case only the actual test method will be executed (step 9); all other
10881059
steps are optional depending on the presence of user code or extension support for the
10891060
corresponding lifecycle callback. For further details on the various lifecycle callbacks
10901061
please consult the respective Javadoc for each annotation and extension.
@@ -1097,6 +1068,7 @@ by implementing <<extensions-intercepting-invocations, `InvocationInterceptor`>>
10971068

10981069
JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions
10991070
that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`,
1071+
`BeforeContainerTemplateInvocationCallback`, `AfterContainerTemplateInvocationCallback`,
11001072
`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and
11011073
`AfterTestExecutionCallback`.
11021074

Loading
Binary file not shown.

junit-jupiter-api/src/main/java/org/junit/jupiter/api/ContainerTemplate.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
* @see TestTemplate
5656
* @see org.junit.jupiter.api.extension.ContainerTemplateInvocationContext
5757
* @see org.junit.jupiter.api.extension.ContainerTemplateInvocationContextProvider
58+
* @see org.junit.jupiter.api.extension.BeforeContainerTemplateInvocationCallback
59+
* @see org.junit.jupiter.api.extension.AfterContainerTemplateInvocationCallback
5860
*/
5961
@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE })
6062
@Retention(RetentionPolicy.RUNTIME)

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterAllCallback.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
* <p>JUnit Jupiter guarantees <em>wrapping behavior</em> for multiple
3535
* registered extensions that implement lifecycle callbacks such as
3636
* {@link BeforeAllCallback}, {@link AfterAllCallback},
37-
* {@link BeforeEachCallback}, {@link AfterEachCallback},
38-
* {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}.
37+
* {@link BeforeContainerTemplateInvocationCallback},
38+
* {@link AfterContainerTemplateInvocationCallback}, {@link BeforeEachCallback},
39+
* {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and
40+
* {@link AfterTestExecutionCallback}.
3941
*
4042
* <p>That means that, given two extensions {@code Extension1} and
4143
* {@code Extension2} with {@code Extension1} registered before
@@ -54,6 +56,8 @@
5456
* @see AfterEachCallback
5557
* @see BeforeTestExecutionCallback
5658
* @see AfterTestExecutionCallback
59+
* @see BeforeContainerTemplateInvocationCallback
60+
* @see AfterContainerTemplateInvocationCallback
5761
*/
5862
@FunctionalInterface
5963
@API(status = STABLE, since = "5.0")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2015-2025 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 org.junit.jupiter.api.extension;
12+
13+
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
14+
15+
import org.apiguardian.api.API;
16+
17+
/**
18+
* {@code AfterContainerTemplateInvocationCallback} defines the API for
19+
* {@link Extension Extensions} that wish to provide additional behavior
20+
* <strong>once</strong> before each invocation of a
21+
* {@linkplain org.junit.jupiter.api.ContainerTemplate container template}.
22+
*
23+
* <p>Concrete implementations often implement
24+
* {@link BeforeContainerTemplateInvocationCallback}
25+
* as well.
26+
*
27+
* <h2>Constructor Requirements</h2>
28+
*
29+
* <p>Consult the documentation in {@link Extension} for details on
30+
* constructor requirements.
31+
*
32+
* <h2>Wrapping Behavior</h2>
33+
*
34+
* <p>JUnit Jupiter guarantees <em>wrapping behavior</em> for multiple
35+
* registered extensions that implement lifecycle callbacks such as
36+
* {@link BeforeAllCallback}, {@link AfterAllCallback},
37+
* {@link AfterContainerTemplateInvocationCallback},
38+
* {@link AfterContainerTemplateInvocationCallback}, {@link BeforeEachCallback},
39+
* {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and
40+
* {@link AfterTestExecutionCallback}.
41+
*
42+
* <p>That means that, given two extensions {@code Extension1} and
43+
* {@code Extension2} with {@code Extension1} registered before
44+
* {@code Extension2}, any "before" callbacks implemented by {@code Extension1}
45+
* are guaranteed to execute before any "before" callbacks implemented by
46+
* {@code Extension2}. Similarly, given the two same two extensions registered
47+
* in the same order, any "after" callbacks implemented by {@code Extension1}
48+
* are guaranteed to execute after any "after" callbacks implemented by
49+
* {@code Extension2}. {@code Extension1} is therefore said to <em>wrap</em>
50+
* {@code Extension2}.
51+
*
52+
* @since 5.13
53+
* @see org.junit.jupiter.api.ContainerTemplate
54+
* @see BeforeContainerTemplateInvocationCallback
55+
* @see BeforeAllCallback
56+
* @see AfterAllCallback
57+
* @see BeforeEachCallback
58+
* @see AfterEachCallback
59+
* @see BeforeTestExecutionCallback
60+
* @see AfterTestExecutionCallback
61+
*/
62+
@FunctionalInterface
63+
@API(status = EXPERIMENTAL, since = "5.13")
64+
public interface AfterContainerTemplateInvocationCallback extends Extension {
65+
66+
/**
67+
* Callback that is invoked <em>after</em> each invocation of a container
68+
* template.
69+
*
70+
* @param context the current extension context; never {@code null}
71+
*/
72+
void afterContainerTemplateInvocation(ExtensionContext context) throws Exception;
73+
74+
}

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterEachCallback.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@
3737
* <p>JUnit Jupiter guarantees <em>wrapping behavior</em> for multiple
3838
* registered extensions that implement lifecycle callbacks such as
3939
* {@link BeforeAllCallback}, {@link AfterAllCallback},
40-
* {@link BeforeEachCallback}, {@link AfterEachCallback},
41-
* {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}.
40+
* {@link BeforeContainerTemplateInvocationCallback},
41+
* {@link AfterContainerTemplateInvocationCallback}, {@link BeforeEachCallback},
42+
* {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and
43+
* {@link AfterTestExecutionCallback}.
4244
*
4345
* <p>That means that, given two extensions {@code Extension1} and
4446
* {@code Extension2} with {@code Extension1} registered before
@@ -57,6 +59,8 @@
5759
* @see AfterTestExecutionCallback
5860
* @see BeforeAllCallback
5961
* @see AfterAllCallback
62+
* @see BeforeContainerTemplateInvocationCallback
63+
* @see AfterContainerTemplateInvocationCallback
6064
*/
6165
@FunctionalInterface
6266
@API(status = STABLE, since = "5.0")

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterTestExecutionCallback.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@
3838
* <p>JUnit Jupiter guarantees <em>wrapping behavior</em> for multiple
3939
* registered extensions that implement lifecycle callbacks such as
4040
* {@link BeforeAllCallback}, {@link AfterAllCallback},
41-
* {@link BeforeEachCallback}, {@link AfterEachCallback},
42-
* {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}.
41+
* {@link BeforeContainerTemplateInvocationCallback},
42+
* {@link AfterContainerTemplateInvocationCallback}, {@link BeforeEachCallback},
43+
* {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and
44+
* {@link AfterTestExecutionCallback}.
4345
*
4446
* <p>That means that, given two extensions {@code Extension1} and
4547
* {@code Extension2} with {@code Extension1} registered before
@@ -58,6 +60,8 @@
5860
* @see AfterEachCallback
5961
* @see BeforeAllCallback
6062
* @see AfterAllCallback
63+
* @see BeforeContainerTemplateInvocationCallback
64+
* @see AfterContainerTemplateInvocationCallback
6165
*/
6266
@FunctionalInterface
6367
@API(status = STABLE, since = "5.0")

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeAllCallback.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
* <p>JUnit Jupiter guarantees <em>wrapping behavior</em> for multiple
3535
* registered extensions that implement lifecycle callbacks such as
3636
* {@link BeforeAllCallback}, {@link AfterAllCallback},
37-
* {@link BeforeEachCallback}, {@link AfterEachCallback},
38-
* {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}.
37+
* {@link BeforeContainerTemplateInvocationCallback},
38+
* {@link AfterContainerTemplateInvocationCallback}, {@link BeforeEachCallback},
39+
* {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and
40+
* {@link AfterTestExecutionCallback}.
3941
*
4042
* <p>That means that, given two extensions {@code Extension1} and
4143
* {@code Extension2} with {@code Extension1} registered before
@@ -54,6 +56,8 @@
5456
* @see AfterEachCallback
5557
* @see BeforeTestExecutionCallback
5658
* @see AfterTestExecutionCallback
59+
* @see BeforeContainerTemplateInvocationCallback
60+
* @see AfterContainerTemplateInvocationCallback
5761
*/
5862
@FunctionalInterface
5963
@API(status = STABLE, since = "5.0")

0 commit comments

Comments
 (0)