|
[[extensions]] |
|
== Extension Model |
|
|
|
[[extensions-overview]] |
|
=== Overview |
|
|
|
In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in |
|
JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the |
|
`Extension` API. Note, however, that `Extension` itself is just a marker interface. |
|
|
|
[[extensions-registration]] |
|
=== Registering Extensions |
|
|
|
Extensions can be registered _declaratively_ via |
|
<<extensions-registration-declarative,`@ExtendWith`>>, _programmatically_ via |
|
<<extensions-registration-programmatic,`@RegisterExtension`>>, or _automatically_ via |
|
Java's <<extensions-registration-automatic,`ServiceLoader`>> mechanism. |
|
|
|
[[extensions-registration-declarative]] |
|
==== Declarative Extension Registration |
|
|
|
Developers can register one or more extensions _declaratively_ by annotating a test |
|
interface, test class, test method, or custom _<<writing-tests-meta-annotations,composed |
|
annotation>>_ with `@ExtendWith(...)` and supplying class references for the extensions to |
|
register. As of JUnit Jupiter 5.8, `@ExtendWith` may also be declared on fields or on |
|
parameters in test class constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, |
|
`@BeforeEach`, and `@AfterEach` lifecycle methods. |
|
|
|
For example, to register a `WebServerExtension` for a particular test method, you would |
|
annotate the test method as follows. We assume the `WebServerExtension` starts a local web |
|
server and injects the server's URL into parameters annotated with `@WebServerUrl`. |
|
|
|
[source,java,indent=0] |
|
---- |
|
@Test |
|
@ExtendWith(WebServerExtension.class) |
|
void getProductList(@WebServerUrl String serverUrl) { |
|
WebClient webClient = new WebClient(); |
|
// Use WebClient to connect to web server using serverUrl and verify response |
|
assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); |
|
} |
|
---- |
|
|
|
To register the `WebServerExtension` for all tests in a particular class and its |
|
subclasses, you would annotate the test class as follows. |
|
|
|
[source,java,indent=0] |
|
---- |
|
@ExtendWith(WebServerExtension.class) |
|
class MyTests { |
|
// ... |
|
} |
|
---- |
|
|
|
Multiple extensions can be registered together like this: |
|
|
|
[source,java,indent=0] |
|
---- |
|
@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) |
|
class MyFirstTests { |
|
// ... |
|
} |
|
---- |
|
|
|
As an alternative, multiple extensions can be registered separately like this: |
|
|
|
[source,java,indent=0] |
|
---- |
|
@ExtendWith(DatabaseExtension.class) |
|
@ExtendWith(WebServerExtension.class) |
|
class MySecondTests { |
|
// ... |
|
} |
|
---- |
|
|
|
[TIP] |
|
.Extension Registration Order |
|
==== |
|
Extensions registered declaratively via `@ExtendWith` at the class level, method level, or |
|
parameter level will be executed in the order in which they are declared in the source |
|
code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will |
|
be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. |
|
==== |
|
|
|
If you wish to combine multiple extensions in a reusable way, you can define a custom |
|
_<<writing-tests-meta-annotations,composed annotation>>_ and use `@ExtendWith` as a |
|
_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` |
|
can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. |
|
|
|
[source,java,indent=0] |
|
---- |
|
@Target({ ElementType.TYPE, ElementType.METHOD }) |
|
@Retention(RetentionPolicy.RUNTIME) |
|
@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) |
|
public @interface DatabaseAndWebServerExtension { |
|
} |
|
---- |
|
|
|
The above examples demonstrate how `@ExtendWith` can be applied at the class level or at |
|
the method level; however, for certain use cases it makes sense for an extension to be |
|
registered declaratively at the field or parameter level. Consider a |
|
`RandomNumberExtension` which generates random numbers that can be injected into a field or |
|
via a parameter in a constructor, test method, or lifecycle method. If the extension |
|
provides a `@Random` annotation that is meta-annotated with |
|
`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used |
|
transparently as in the following `RandomNumberDemo` example. |
|
|
|
[source,java,indent=0] |
|
---- |
|
include::{testDir}/example/extensions/Random.java[tags=user_guide] |
|
---- |
|
|
|
[source,java,indent=0] |
|
---- |
|
include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] |
|
---- |
|
|
|
[[extensions-RandomNumberExtension]] |
|
The following code listing provides an example of how one might choose to implement such a |
|
`RandomNumberExtension`. This implementation works for the use cases in |
|
`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for |
|
example, the random number generation support is limited to integers; it uses |
|
`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is |
|
important to note which extension APIs are implemented and for what reasons. |
|
|
|
Specifically, `RandomNumberExtension` implements the following extension APIs: |
|
|
|
- `BeforeAllCallback`: to support static field injection |
|
- `BeforeEachCallback`: to support non-static field injection |
|
- `ParameterResolver`: to support constructor and method injection |
|
|
|
[NOTE] |
|
==== |
|
Ideally, the `RandomNumberExtension` would implement `TestInstancePostProcessor` instead |
|
of `BeforeEachCallback` in order to support non-static field injection immediately after |
|
the test class has been instantiated. |
|
|
|
However, JUnit Jupiter currently does not allow a `TestInstancePostProcessor` to be |
|
registered via `@ExtendWith` on a non-static field (see |
|
link:{junit5-repo}/issues/3437[issue 3437]). In light of that, the `RandomNumberExtension` |
|
implements `BeforeEachCallback` as an alternative approach. |
|
==== |
|
|
|
[source,java,indent=0] |
|
---- |
|
include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] |
|
---- |
|
|
|
[TIP] |
|
.Extension Registration Order for `@ExtendWith` on Fields |
|
==== |
|
Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative |
|
to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is |
|
deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered |
|
using the `@Order` annotation. See the <<extensions-registration-programmatic-order, |
|
Extension Registration Order>> tip for `@RegisterExtension` fields for details. |
|
==== |
|
|
|
NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on |
|
<<extensions-registration-programmatic-static-fields, Static Fields>> and |
|
<<extensions-registration-programmatic-instance-fields, Instance Fields>> for |
|
`@RegisterExtension` fields also applies to `@ExtendWith` fields. |
|
|
|
[[extensions-registration-programmatic]] |
|
==== Programmatic Extension Registration |
|
|
|
Developers can register extensions _programmatically_ by annotating fields in test classes |
|
with `{RegisterExtension}`. |
|
|
|
When an extension is registered _declaratively_ via |
|
<<extensions-registration-declarative,`@ExtendWith`>>, it can typically only be configured |
|
via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it |
|
can be configured _programmatically_ -- for example, in order to pass arguments to the |
|
extension's constructor, a static factory method, or a builder API. |
|
|
|
[[extensions-registration-programmatic-order]] |
|
[TIP] |
|
.Extension Registration Order |
|
==== |
|
By default, extensions registered programmatically via `@RegisterExtension` or |
|
declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is |
|
deterministic but intentionally nonobvious. This ensures that subsequent runs of a test |
|
suite execute extensions in the same order, thereby allowing for repeatable builds. |
|
However, there are times when extensions need to be registered in an explicit order. To |
|
achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. |
|
|
|
Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be |
|
ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This |
|
allows `@Order` annotated extension fields to be explicitly ordered before or after |
|
non-annotated extension fields. Extensions with an explicit order value less than the |
|
default order value will be registered before non-annotated extensions. Similarly, |
|
extensions with an explicit order value greater than the default order value will be |
|
registered after non-annotated extensions. For example, assigning an extension an explicit |
|
order value that is greater than the default order value allows _before_ callback |
|
extensions to be registered last and _after_ callback extensions to be registered first, |
|
relative to other programmatically registered extensions. |
|
==== |
|
|
|
NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be |
|
either `static` or non-static. |
|
|
|
[[extensions-registration-programmatic-static-fields]] |
|
===== Static Fields |
|
|
|
If a `@RegisterExtension` field is `static`, the extension will be registered after |
|
extensions that are registered at the class level via `@ExtendWith`. Such _static |
|
extensions_ are not limited in which extension APIs they can implement. Extensions |
|
registered via static fields may therefore implement class-level and instance-level |
|
extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, |
|
`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level |
|
extension APIs such as `BeforeEachCallback`, etc. |
|
|
|
In the following example, the `server` field in the test class is initialized |
|
programmatically by using a builder pattern supported by the `WebServerExtension`. The |
|
configured `WebServerExtension` will be automatically registered as an extension at the |
|
class level -- for example, in order to start the server before all tests in the class |
|
and then stop the server after all tests in the class have completed. In addition, static |
|
lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, |
|
`@AfterEach`, and `@Test` methods can access the instance of the extension via the |
|
`server` field if necessary. |
|
|
|
[source,java,indent=0] |
|
.Registering an extension via a static field in Java |
|
---- |
|
include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] |
|
---- |
|
|
|
[[extensions-registration-programmatic-static-fields-kotlin]] |
|
====== Static Fields in Kotlin |
|
|
|
The Kotlin programming language does not have the concept of a `static` field. However, |
|
the compiler can be instructed to generate a `private static` field using the `@JvmStatic` |
|
annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, |
|
you can use the `@JvmField` annotation instead. |
|
|
|
The following example is a version of the `WebServerDemo` from the previous section that |
|
has been ported to Kotlin. |
|
|
|
[source,kotlin,indent=0] |
|
.Registering an extension via a static field in Kotlin |
|
---- |
|
include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] |
|
---- |
|
|
|
[[extensions-registration-programmatic-instance-fields]] |
|
===== Instance Fields |
|
|
|
If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension |
|
will be registered after the test class has been instantiated and after each registered |
|
`TestInstancePostProcessor` has been given a chance to post-process the test instance |
|
(potentially injecting the instance of the extension to be used into the annotated |
|
field). Thus, if such an _instance extension_ implements class-level or instance-level |
|
extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or |
|
`TestInstancePostProcessor`, those APIs will not be honored. By default, an instance |
|
extension will be registered _after_ extensions that are registered at the method level |
|
via `@ExtendWith`; however, if the test class is configured with |
|
`@TestInstance(Lifecycle.PER_CLASS)` semantics, an instance extension will be registered |
|
_before_ extensions that are registered at the method level via `@ExtendWith`. |
|
|
|
In the following example, the `docs` field in the test class is initialized |
|
programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result |
|
to the static `forPath()` factory method in the `DocumentationExtension`. The configured |
|
`DocumentationExtension` will be automatically registered as an extension at the method |
|
level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the |
|
instance of the extension via the `docs` field if necessary. |
|
|
|
[source,java,indent=0] |
|
.An extension registered via an instance field |
|
---- |
|
include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] |
|
---- |
|
|
|
[[extensions-registration-automatic]] |
|
==== Automatic Extension Registration |
|
|
|
In addition to <<extensions-registration-declarative,declarative extension registration>> |
|
and <<extensions-registration-programmatic,programmatic extension registration>> support |
|
using annotations, JUnit Jupiter also supports _global extension registration_ via Java's |
|
`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and |
|
automatically registered based on what is available in the classpath. |
|
|
|
Specifically, a custom extension can be registered by supplying its fully qualified class |
|
name in a file named `org.junit.jupiter.api.extension.Extension` within the |
|
`/META-INF/services` folder in its enclosing JAR file. |
|
|
|
[[extensions-registration-automatic-enabling]] |
|
===== Enabling Automatic Extension Detection |
|
|
|
Auto-detection is an advanced feature and is therefore not enabled by default. To enable |
|
it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to |
|
`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in |
|
the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform |
|
configuration file (see <<running-tests-config-params>> for details). |
|
|
|
For example, to enable auto-detection of extensions, you can start your JVM with the |
|
following system property. |
|
|
|
`-Djunit.jupiter.extensions.autodetection.enabled=true` |
|
|
|
When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism |
|
will be added to the extension registry after JUnit Jupiter's global extensions (e.g., |
|
support for `TestInfo`, `TestReporter`, etc.). |
|
|
|
[[extensions-registration-inheritance]] |
|
==== Extension Inheritance |
|
|
|
Registered extensions are inherited within test class hierarchies with top-down |
|
semantics. Similarly, extensions registered at the class-level are inherited at the |
|
method-level. Furthermore, a specific extension implementation can only be registered |
|
once for a given extension context and its parent contexts. Consequently, any attempt to |
|
register a duplicate extension implementation will be ignored. |
|
|
|
[[extensions-conditions]] |
|
=== Conditional Test Execution |
|
|
|
`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test |
|
execution_. |
|
|
|
An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to |
|
determine if all the tests it contains should be executed based on the supplied |
|
`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to |
|
determine if a given test method should be executed based on the supplied |
|
`ExtensionContext`. |
|
|
|
When multiple `ExecutionCondition` extensions are registered, a container or test is |
|
disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee |
|
that a condition is evaluated because another extension might have already caused a |
|
container or test to be disabled. In other words, the evaluation works like the |
|
short-circuiting boolean OR operator. |
|
|
|
See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. |
|
|
|
[[extensions-conditions-deactivation]] |
|
==== Deactivating Conditions |
|
|
|
Sometimes it can be useful to run a test suite _without_ certain conditions being active. |
|
For example, you may wish to run tests even if they are annotated with `@Disabled` in |
|
order to see if they are still _broken_. To do this, provide a pattern for the |
|
`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which |
|
conditions should be deactivated (i.e., not evaluated) for the current test run. The |
|
pattern can be supplied as a JVM system property, as a _configuration parameter_ in the |
|
`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform |
|
configuration file (see <<running-tests-config-params>> for details). |
|
|
|
For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the |
|
following system property. |
|
|
|
`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` |
|
|
|
[[extensions-conditions-deactivation-patterns]] |
|
===== Pattern Matching Syntax |
|
|
|
Refer to <<running-tests-config-params-deactivation-pattern>> for details. |
|
|
|
[[extensions-test-instance-pre-construct-callback]] |
|
=== Test Instance Pre-construct Callback |
|
|
|
`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked |
|
_prior_ to test instances being constructed (by a constructor call or via |
|
`{TestInstanceFactory}`). |
|
|
|
This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful |
|
in combination with other extensions to prepare constructor parameters or keeping track of test |
|
instances and their lifecycle. |
|
|
|
[[extensions-test-instance-factories]] |
|
=== Test Instance Factories |
|
|
|
`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class |
|
instances. |
|
|
|
Common use cases include acquiring the test instance from a dependency injection |
|
framework or invoking a static factory method to create the test class instance. |
|
|
|
If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ |
|
constructor for the test class to instantiate it, potentially resolving constructor |
|
arguments via registered `ParameterResolver` extensions. |
|
|
|
Extensions that implement `TestInstanceFactory` can be registered on test interfaces, |
|
top-level test classes, or `@Nested` test classes. |
|
|
|
[WARNING] |
|
==== |
|
Registering multiple extensions that implement `TestInstanceFactory` for any single class |
|
will result in an exception being thrown for all tests in that class, in any subclass, |
|
and in any nested class. Note that any `TestInstanceFactory` registered in a superclass |
|
or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is |
|
the user's responsibility to ensure that only a single `TestInstanceFactory` is |
|
registered for any specific test class. |
|
==== |
|
|
|
[[extensions-test-instance-post-processing]] |
|
=== Test Instance Post-processing |
|
|
|
`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post |
|
process_ test instances. |
|
|
|
Common use cases include injecting dependencies into the test instance, invoking custom |
|
initialization methods on the test instance, etc. |
|
|
|
For a concrete example, consult the source code for the `{MockitoExtension}` and the |
|
`{SpringExtension}`. |
|
|
|
[[extensions-test-instance-pre-destroy-callback]] |
|
=== Test Instance Pre-destroy Callback |
|
|
|
`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process |
|
test instances _after_ they have been used in tests and _before_ they are destroyed. |
|
|
|
Common use cases include cleaning dependencies that have been injected into the |
|
test instance, invoking custom de-initialization methods on the test instance, etc. |
|
|
|
[[extensions-parameter-resolution]] |
|
=== Parameter Resolution |
|
|
|
`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at |
|
runtime. |
|
|
|
If a _test class_ constructor, _test method_, or _lifecycle method_ (see |
|
<<writing-tests-definitions>>) declares a parameter, the parameter must be _resolved_ at |
|
runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see |
|
`{TestInfoParameterResolver}`) or <<extensions-registration,registered by the user>>. |
|
Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any |
|
combination thereof. |
|
|
|
If you wish to implement a custom `{ParameterResolver}` that resolves parameters based |
|
solely on the type of the parameter, you may find it convenient to extend the |
|
`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. |
|
|
|
For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, |
|
`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. |
|
|
|
[WARNING] |
|
==== |
|
Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, |
|
looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` |
|
API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` |
|
test class). |
|
|
|
The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore |
|
includes the following convenience methods for correctly looking up annotations on |
|
parameters. Extension authors are strongly encouraged to use these methods instead of |
|
those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. |
|
|
|
* `boolean isAnnotated(Class<? extends Annotation> annotationType)` |
|
* `Optional<A> findAnnotation(Class<A> annotationType)` |
|
* `List<A> findRepeatableAnnotations(Class<A> annotationType)` |
|
==== |
|
|
|
[NOTE] |
|
==== |
|
Other extensions can also leverage registered `ParameterResolvers` for method and |
|
constructor invocations, using the `{ExecutableInvoker}` available via the |
|
`getExecutableInvoker()` method in the `ExtensionContext`. |
|
==== |
|
|
|
[[extensions-test-result-processing]] |
|
=== Test Result Processing |
|
|
|
`{TestWatcher}` defines the API for extensions that wish to process the results of _test |
|
method_ executions. Specifically, a `TestWatcher` will be invoked with contextual |
|
information for the following events. |
|
|
|
* `testDisabled`: invoked after a disabled _test method_ has been skipped |
|
* `testSuccessful`: invoked after a _test method_ has completed successfully |
|
* `testAborted`: invoked after a _test method_ has been aborted |
|
* `testFailed`: invoked after a _test method_ has failed |
|
|
|
NOTE: In contrast to the definition of "test method" presented in |
|
<<writing-tests-definitions>>, in this context _test method_ refers to any `@Test` method |
|
or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). |
|
|
|
Extensions implementing this interface can be registered at the class level, instance |
|
level, or method level. When registered at the class level, a `TestWatcher` will be |
|
invoked for any contained _test method_ including those in `@Nested` classes. When |
|
registered at the method level, a `TestWatcher` will only be invoked for the _test method_ |
|
for which it was registered. |
|
|
|
[WARNING] |
|
==== |
|
If a `TestWatcher` is registered via a non-static (instance) field – for example, using |
|
`@RegisterExtension` – and the test class is configured with |
|
`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the |
|
`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for |
|
example, `@RepeatedTest` or `@ParameterizedTest`). |
|
|
|
To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is |
|
therefore recommended that the `TestWatcher` be registered at the class level with |
|
`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. |
|
==== |
|
|
|
If there is a failure at the class level — for example, an exception thrown by a |
|
`@BeforeAll` method — no test results will be reported. Similarly, if the test class is |
|
disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be |
|
reported. |
|
|
|
In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely |
|
influence the execution of tests. Consequently, any exception thrown by a method in the |
|
`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate |
|
or fail test execution. |
|
|
|
[WARNING] |
|
==== |
|
Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the |
|
provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are |
|
invoked (see <<extensions-keeping-state>>). You can use the parent context's `Store` to |
|
work with such resources. |
|
==== |
|
|
|
[[extensions-lifecycle-callbacks]] |
|
=== Test Lifecycle Callbacks |
|
|
|
The following interfaces define the APIs for extending tests at various points in the |
|
test execution lifecycle. Consult the following sections for examples and the Javadoc for |
|
each of these interfaces in the `{extension-api-package}` package for further details. |
|
|
|
* `{BeforeAllCallback}` |
|
** `{BeforeEachCallback}` |
|
*** `{BeforeTestExecutionCallback}` |
|
*** `{AfterTestExecutionCallback}` |
|
** `{AfterEachCallback}` |
|
* `{AfterAllCallback}` |
|
|
|
.Implementing Multiple Extension APIs |
|
NOTE: Extension developers may choose to implement any number of these interfaces |
|
within a single extension. Consult the source code of the `{SpringExtension}` for a |
|
concrete example. |
|
|
|
[[extensions-lifecycle-callbacks-before-after-execution]] |
|
==== Before and After Test Execution Callbacks |
|
|
|
`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for |
|
`Extensions` that wish to add behavior that will be executed _immediately before_ and |
|
_immediately after_ a test method is executed, respectively. As such, these callbacks are |
|
well suited for timing, tracing, and similar use cases. If you need to implement |
|
callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement |
|
`BeforeEachCallback` and `AfterEachCallback` instead. |
|
|
|
The following example shows how to use these callbacks to calculate and log the execution |
|
time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` |
|
and `AfterTestExecutionCallback` in order to time and log the test execution. |
|
|
|
[[extensions-lifecycle-callbacks-timing-extension]] |
|
[source,java,indent=0] |
|
.An extension that times and logs the execution of test methods |
|
---- |
|
include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] |
|
---- |
|
|
|
Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, |
|
its tests will have this timing applied when they execute. |
|
|
|
[source,java,indent=0] |
|
.A test class that uses the example TimingExtension |
|
---- |
|
include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] |
|
---- |
|
|
|
The following is an example of the logging produced when `TimingExtensionTests` is run. |
|
|
|
.... |
|
INFO: Method [sleep20ms] took 24 ms. |
|
INFO: Method [sleep50ms] took 53 ms. |
|
.... |
|
|
|
[[extensions-exception-handling]] |
|
=== Exception Handling |
|
|
|
Exceptions thrown during the test execution may be intercepted and handled accordingly |
|
before propagating further, so that certain actions like error logging or resource releasing |
|
may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that |
|
wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` |
|
and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, |
|
`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. |
|
|
|
The following example shows an extension which will swallow all instances of `IOException` |
|
but rethrow any other type of exception. |
|
|
|
[source,java,indent=0] |
|
.An exception handling extension that filters IOExceptions in test execution |
|
---- |
|
include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] |
|
---- |
|
|
|
Another example shows how to record the state of an application under test exactly at |
|
the point of unexpected exception being thrown during setup and cleanup. Note that unlike |
|
relying on lifecycle callbacks, which may or may not be executed depending on the test |
|
status, this solution guarantees execution immediately after failing `@BeforeAll`, |
|
`@BeforeEach`, `@AfterEach` or `@AfterAll`. |
|
|
|
[source,java,indent=0] |
|
.An exception handling extension that records application state on error |
|
---- |
|
include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] |
|
---- |
|
|
|
Multiple execution exception handlers may be invoked for the same lifecycle method in |
|
order of declaration. If one of the handlers swallows the handled exception, subsequent |
|
ones will not be executed, and no failure will be propagated to JUnit engine, as if the |
|
exception was never thrown. Handlers may also choose to rethrow the exception or throw |
|
a different one, potentially wrapping the original. |
|
|
|
Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle |
|
exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, |
|
while handlers for `BeforeEach` and `AfterEach` may be also registered for individual |
|
test methods. |
|
|
|
[source,java,indent=0] |
|
.Registering multiple exception handling extensions |
|
---- |
|
include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] |
|
---- |
|
|
|
[[extensions-intercepting-invocations]] |
|
=== Intercepting Invocations |
|
|
|
`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to |
|
test code. |
|
|
|
The following example shows an extension that executes all test methods in Swing's Event |
|
Dispatch Thread. |
|
|
|
[source,java,indent=0] |
|
.An extension that executes tests in a user-defined thread |
|
---- |
|
include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] |
|
---- |
|
|
|
[[extensions-test-templates]] |
|
=== Providing Invocation Contexts for Test Templates |
|
|
|
A `{TestTemplate}` method can only be executed when at least one |
|
`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible |
|
for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may |
|
specify a custom display name and a list of additional extensions that will only be used |
|
for the next invocation of the `{TestTemplate}` method. |
|
|
|
The following example shows how to write a test template as well as how to register and |
|
implement a `{TestTemplateInvocationContextProvider}`. |
|
|
|
[source,java,indent=0] |
|
.A test template with accompanying extension |
|
---- |
|
include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] |
|
---- |
|
|
|
In this example, the test template will be invoked twice. The display names of the |
|
invocations will be `apple` and `banana` as specified by the invocation context. Each |
|
invocation registers a custom `{ParameterResolver}` which is used to resolve the method |
|
parameter. The output when using the `ConsoleLauncher` is as follows. |
|
|
|
.... |
|
└─ testTemplate(String) ✔ |
|
├─ apple ✔ |
|
└─ banana ✔ |
|
.... |
|
|
|
The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for |
|
implementing different kinds of tests that rely on repetitive invocation of a test-like |
|
method albeit in different contexts — for example, with different parameters, by preparing |
|
the test class instance differently, or multiple times without modifying the context. |
|
Please refer to the implementations of <<writing-tests-repeated-tests>> or |
|
<<writing-tests-parameterized-tests>> which use this extension point to provide their |
|
functionality. |
|
|
|
|
|
[[extensions-keeping-state]] |
|
=== Keeping State in Extensions |
|
|
|
Usually, an extension is instantiated only once. So the question becomes relevant: How do |
|
you keep the state from one invocation of an extension to the next? The |
|
`ExtensionContext` API provides a `Store` exactly for this purpose. Extensions may put |
|
values into a store for later retrieval. See the |
|
`<<extensions-lifecycle-callbacks-timing-extension, TimingExtension>>` for an example of |
|
using the `Store` with a method-level scope. It is important to remember that values |
|
stored in an `ExtensionContext` during test execution will not be available in the |
|
surrounding `ExtensionContext`. Since `ExtensionContexts` may be nested, the scope of |
|
inner contexts may also be limited. Consult the corresponding Javadoc for details on the |
|
methods available for storing and retrieving values via the `{ExtensionContext_Store}`. |
|
|
|
.`ExtensionContext.Store.CloseableResource` |
|
NOTE: An extension context store is bound to its extension context lifecycle. When an |
|
extension context lifecycle ends it closes its associated store. All stored values |
|
that are instances of `CloseableResource` are notified by an invocation of their `close()` |
|
method in the inverse order they were added in. |
|
|
|
[[extensions-supported-utilities]] |
|
=== Supported Utilities in Extensions |
|
|
|
The `junit-platform-commons` artifact exposes a package named |
|
`{junit-platform-support-package}` that contains _maintained_ utility methods for working |
|
with annotations, classes, reflection, and classpath scanning tasks. `TestEngine` and |
|
`Extension` authors are encouraged to use these supported methods in order to align with |
|
the behavior of the JUnit Platform. |
|
|
|
[[extensions-supported-utilities-annotations]] |
|
==== Annotation Support |
|
|
|
`AnnotationSupport` provides static utility methods that operate on annotated elements |
|
(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). |
|
These include methods to check whether an element is annotated or meta-annotated with a |
|
particular annotation, to search for specific annotations, and to find annotated methods |
|
and fields in a class or interface. Some of these methods search on implemented |
|
interfaces and within class hierarchies to find annotations. Consult the Javadoc for |
|
`{AnnotationSupport}` for further details. |
|
|
|
[[extensions-supported-utilities-classes]] |
|
==== Class Support |
|
|
|
`ClassSupport` provides static utility methods for working with classes (i.e., instances |
|
of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. |
|
|
|
[[extensions-supported-utilities-reflection]] |
|
==== Reflection Support |
|
|
|
`ReflectionSupport` provides static utility methods that augment the standard JDK |
|
reflection and class-loading mechanisms. These include methods to scan the classpath in |
|
search of classes matching specified predicates, to load and create new instances of a |
|
class, and to find and invoke methods. Some of these methods traverse class hierarchies |
|
to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further |
|
details. |
|
|
|
[[extensions-supported-utilities-modifier]] |
|
==== Modifier Support |
|
|
|
`ModifierSupport` provides static utility methods for working with member and class |
|
modifiers -- for example, to determine if a member is declared as `public`, `private`, |
|
`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further |
|
details. |
|
|
|
|
|
[[extensions-execution-order]] |
|
=== Relative Execution Order of User Code and Extensions |
|
|
|
When executing a test class that contains one or more test methods, a number of extension |
|
callbacks are called in addition to the user-supplied test and lifecycle methods. |
|
|
|
NOTE: See also: <<writing-tests-test-execution-order>> |
|
|
|
[[extensions-execution-order-overview]] |
|
==== User and Extension Code |
|
|
|
The following diagram illustrates the relative order of user-supplied code and extension |
|
code. User-supplied test and lifecycle methods are shown in orange, with callback code |
|
implemented by extensions shown in blue. The grey box denotes the execution of a single |
|
test method and will be repeated for every test method in the test class. |
|
|
|
:figure-caption: User code and extension code |
|
|
|
[#extensions-execution-order-diagram,reftext='{figure-caption}'] |
|
image::extensions_lifecycle.png[caption='',title='{figure-caption}'] |
|
|
|
The following table further explains the sixteen steps in the |
|
<<extensions-execution-order-diagram>> diagram. |
|
|
|
[cols="5,15,80"] |
|
|=== |
|
| Step | Interface/Annotation | Description |
|
|
|
| 1 |
|
| interface `org.junit.jupiter.api.extension.BeforeAllCallback` |
|
| extension code executed before all tests of the container are executed |
|
|
|
| 2 |
|
| annotation `org.junit.jupiter.api.BeforeAll` |
|
| user code executed before all tests of the container are executed |
|
|
|
| 3 |
|
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler |
|
#handleBeforeAllMethodExecutionException` |
|
| extension code for handling exceptions thrown from `@BeforeAll` methods |
|
|
|
| 4 |
|
| interface `org.junit.jupiter.api.extension.BeforeEachCallback` |
|
| extension code executed before each test is executed |
|
|
|
| 5 |
|
| annotation `org.junit.jupiter.api.BeforeEach` |
|
| user code executed before each test is executed |
|
|
|
| 6 |
|
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler |
|
#handleBeforeEachMethodExecutionException` |
|
| extension code for handling exceptions thrown from `@BeforeEach` methods |
|
|
|
| 7 |
|
| interface `org.junit.jupiter.api.extension.BeforeTestExecutionCallback` |
|
| extension code executed immediately before a test is executed |
|
|
|
| 8 |
|
| annotation `org.junit.jupiter.api.Test` |
|
| user code of the actual test method |
|
|
|
| 9 |
|
| interface `org.junit.jupiter.api.extension.TestExecutionExceptionHandler` |
|
| extension code for handling exceptions thrown during a test |
|
|
|
| 10 |
|
| interface `org.junit.jupiter.api.extension.AfterTestExecutionCallback` |
|
| extension code executed immediately after test execution and its corresponding exception handlers |
|
|
|
| 11 |
|
| annotation `org.junit.jupiter.api.AfterEach` |
|
| user code executed after each test is executed |
|
|
|
| 12 |
|
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler |
|
#handleAfterEachMethodExecutionException` |
|
| extension code for handling exceptions thrown from `@AfterEach` methods |
|
|
|
| 13 |
|
| interface `org.junit.jupiter.api.extension.AfterEachCallback` |
|
| extension code executed after each test is executed |
|
|
|
| 14 |
|
| annotation `org.junit.jupiter.api.AfterAll` |
|
| user code executed after all tests of the container are executed |
|
|
|
| 15 |
|
| interface `org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler |
|
#handleAfterAllMethodExecutionException` |
|
| extension code for handling exceptions thrown from `@AfterAll` methods |
|
|
|
| 16 |
|
| interface `org.junit.jupiter.api.extension.AfterAllCallback` |
|
| extension code executed after all tests of the container are executed |
|
|
|
|=== |
|
|
|
In the simplest case only the actual test method will be executed (step 8); all other |
|
steps are optional depending on the presence of user code or extension support for the |
|
corresponding lifecycle callback. For further details on the various lifecycle callbacks |
|
please consult the respective Javadoc for each annotation and extension. |
|
|
|
All invocations of user code methods in the above table can additionally be intercepted |
|
by implementing <<extensions-intercepting-invocations, `InvocationInterceptor`>>. |
|
|
|
[[extensions-execution-order-wrapping-behavior]] |
|
==== Wrapping Behavior of Callbacks |
|
|
|
JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions |
|
that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, |
|
`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and |
|
`AfterTestExecutionCallback`. |
|
|
|
That means that, given two extensions `Extension1` and `Extension2` with `Extension1` |
|
registered before `Extension2`, any "before" callbacks implemented by `Extension1` are |
|
guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. |
|
Similarly, given the two same two extensions registered in the same order, any "after" |
|
callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" |
|
callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ |
|
`Extension2`. |
|
|
|
JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies |
|
for user-supplied _lifecycle methods_ (see <<writing-tests-definitions>>). |
|
|
|
* `@BeforeAll` methods are inherited from superclasses as long as they are not _hidden_, |
|
_overridden_, or _superseded_ (i.e., replaced based on signature only, irrespective of |
|
Java's visibility rules). Furthermore, `@BeforeAll` methods from superclasses will be |
|
executed **before** `@BeforeAll` methods in subclasses. |
|
** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they |
|
are not _hidden_ or _overridden_, and `@BeforeAll` methods from an interface will be |
|
executed **before** `@BeforeAll` methods in the class that implements the interface. |
|
* `@AfterAll` methods are inherited from superclasses as long as they are not _hidden_, |
|
_overridden_, or _superseded_ (i.e., replaced based on signature only, irrespective of |
|
Java's visibility rules). Furthermore, `@AfterAll` methods from superclasses will be |
|
executed **after** `@AfterAll` methods in subclasses. |
|
** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they |
|
are not _hidden_ or _overridden_, and `@AfterAll` methods from an interface will be |
|
executed **after** `@AfterAll` methods in the class that implements the interface. |
|
* `@BeforeEach` methods are inherited from superclasses as long as they are not |
|
_overridden_ or _superseded_ (i.e., replaced based on signature only, irrespective of |
|
Java's visibility rules). Furthermore, `@BeforeEach` methods from superclasses will be |
|
executed **before** `@BeforeEach` methods in subclasses. |
|
** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as |
|
long as they are not _overridden_, and `@BeforeEach` default methods will be executed |
|
**before** `@BeforeEach` methods in the class that implements the interface. |
|
* `@AfterEach` methods are inherited from superclasses as long as they are not |
|
_overridden_ or _superseded_ (i.e., replaced based on signature only, irrespective of |
|
Java's visibility rules). Furthermore, `@AfterEach` methods from superclasses will be |
|
executed **after** `@AfterEach` methods in subclasses. |
|
** Similarly, `@AfterEach` methods declared as interface default methods are inherited as |
|
long as they are not _overridden_, and `@AfterEach` default methods will be executed |
|
**after** `@AfterEach` methods in the class that implements the interface. |
|
|
|
The following examples demonstrate this behavior. Please note that the examples do not |
|
actually do anything realistic. Instead, they mimic common scenarios for testing |
|
interactions with the database. All methods imported statically from the `Logger` class |
|
log contextual information in order to help us better understand the execution order of |
|
user-supplied callback methods and callback methods in extensions. |
|
|
|
[source,java,indent=0] |
|
.Extension1 |
|
---- |
|
include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] |
|
---- |
|
|
|
[source,java,indent=0] |
|
.Extension2 |
|
---- |
|
include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] |
|
---- |
|
|
|
[source,java,indent=0] |
|
.AbstractDatabaseTests |
|
---- |
|
include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] |
|
---- |
|
|
|
[source,java,indent=0] |
|
.DatabaseTestsDemo |
|
---- |
|
include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] |
|
---- |
|
|
|
When the `DatabaseTestsDemo` test class is executed, the following is logged. |
|
|
|
---- |
|
@BeforeAll AbstractDatabaseTests.createDatabase() |
|
@BeforeAll DatabaseTestsDemo.beforeAll() |
|
Extension1.beforeEach() |
|
Extension2.beforeEach() |
|
@BeforeEach AbstractDatabaseTests.connectToDatabase() |
|
@BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() |
|
@Test DatabaseTestsDemo.testDatabaseFunctionality() |
|
@AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() |
|
@AfterEach AbstractDatabaseTests.disconnectFromDatabase() |
|
Extension2.afterEach() |
|
Extension1.afterEach() |
|
@BeforeAll DatabaseTestsDemo.afterAll() |
|
@AfterAll AbstractDatabaseTests.destroyDatabase() |
|
---- |
|
|
|
The following sequence diagram helps to shed further light on what actually goes on within |
|
the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. |
|
|
|
|
|
|
|
|
|
|
|
|
|
image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] |
|
|
|
JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods |
|
that are declared within a _single_ test class or test interface. It may at times appear |
|
that JUnit Jupiter invokes such methods in alphabetical order. However, that is not |
|
precisely true. The ordering is analogous to the ordering for `@Test` methods within a |
|
single test class. |
|
|
|
[NOTE] |
|
==== |
|
Lifecycle methods that are declared within a _single_ test class or test interface will be |
|
ordered using an algorithm that is deterministic but intentionally non-obvious. This |
|
ensures that subsequent runs of a test suite execute lifecycle methods in the same order, |
|
thereby allowing for repeatable builds. |
|
==== |
|
|
|
In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle |
|
methods declared within a single test class or test interface. |
|
|
|
The following example demonstrates this behavior. Specifically, the lifecycle method |
|
configuration is _broken_ due to the order in which the locally declared lifecycle methods |
|
are executed. |
|
|
|
* Test data is inserted _before_ the database connection has been opened, which results in |
|
a failure to connect to the database. |
|
* The database connection is closed _before_ deleting the test data, which results in a |
|
failure to connect to the database. |
|
|
|
[source,java,indent=0] |
|
.BrokenLifecycleMethodConfigDemo |
|
---- |
|
include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] |
|
---- |
|
|
|
When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. |
|
|
|
---- |
|
Extension1.beforeEach() |
|
Extension2.beforeEach() |
|
@BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() |
|
@BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() |
|
@Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() |
|
@AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() |
|
@AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() |
|
Extension2.afterEach() |
|
Extension1.afterEach() |
|
---- |
|
|
|
The following sequence diagram helps to shed further light on what actually goes on within |
|
the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. |
|
|
|
|
|
|
|
|
|
|
|
|
|
image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] |
|
|
|
[TIP] |
|
==== |
|
Due to the aforementioned behavior, the JUnit Team recommends that developers declare at |
|
most one of each type of _lifecycle method_ (see <<writing-tests-definitions>>) per test |
|
class or test interface unless there are no dependencies between such lifecycle methods. |
|
==== |
|
|