Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion documentation/src/docs/asciidoc/link-attributes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ endif::[]
:BeforeAllCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeAllCallback.html[BeforeAllCallback]
:BeforeEachCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeEachCallback.html[BeforeEachCallback]
:BeforeTestExecutionCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeTestExecutionCallback.html[BeforeTestExecutionCallback]
:EnableTestScopedConstructorContext: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/EnableTestScopedConstructorContext.html[@EnableTestScopedConstructorContext]
:ExecutableInvoker: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExecutableInvoker.html[ExecutableInvoker]
:ExecutionCondition: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExecutionCondition.html[ExecutionCondition]
:ExtendWith: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtendWith.html[@ExtendWith]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ JUnit repository on GitHub.
extensions.
* Allow determining "shared resources" at runtime via the new `@ResourceLock#providers`
attribute that accepts implementations of `ResourceLocksProvider`.
* `@EnableTestScopedConstructorContext` has been added to enable the use of a test-scoped
`ExtensionContext` while instantiating the test instance.
The behavior enabled by the annotation is expected to eventually become the default in
future versions of JUnit Jupiter.
* Extensions that participate in the construction of test class instances may override the
`getExtensionContextScopeDuringTestClassInstanceConstruction()` method to enable using a
test-scoped `ExtensionContext` in `Extension` methods called during test class instance
construction. This behavior will become the default in future versions of JUnit.
* `@TempDir` is now supported on test class constructors.


Expand Down
35 changes: 22 additions & 13 deletions documentation/src/docs/asciidoc/user-guide/extensions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,10 @@ instances and their lifecycle.

[NOTE]
====
You may annotate your extension with `{EnableTestScopedConstructorContext}` for revised
handling of `CloseableResource` and to make test-specific data available to your implementation.
You may override the
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
`TEST_SCOPED` for revised handling of `CloseableResource` and to make test-specific data
available to your implementation.
====

[[extensions-test-instance-factories]]
Expand Down Expand Up @@ -415,8 +417,10 @@ registered for any specific test class.

[NOTE]
====
You may annotate your extension with `{EnableTestScopedConstructorContext}` for revised
handling of `CloseableResource` and to make test-specific data available to your implementation.
You may override the
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
`TEST_SCOPED` for revised handling of `CloseableResource` and to make test-specific data
available to your implementation.
====

[[extensions-test-instance-post-processing]]
Expand All @@ -433,8 +437,10 @@ For a concrete example, consult the source code for the `{MockitoExtension}` and

[NOTE]
====
You may annotate your extension with `{EnableTestScopedConstructorContext}` for revised
handling of `CloseableResource` and to make test-specific data available to your implementation.
You may override the
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
`TEST_SCOPED` for revised handling of `CloseableResource` and to make test-specific data
available to your implementation.
====

[[extensions-test-instance-pre-destroy-callback]]
Expand Down Expand Up @@ -485,10 +491,12 @@ those provided in `java.lang.reflect.Parameter` in order to avoid this bug in th

[NOTE]
====
You may annotate your extension with `{EnableTestScopedConstructorContext}` to support
injecting test specific data into constructor parameters of the test instance.
The annotation makes JUnit use a test-specific `ExtensionContext` while resolving
constructor parameters, unless the lifecycle is set to `TestInstance.Lifecycle.PER_CLASS`.
You may override the
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
`TEST_SCOPED` to support injecting test specific data into constructor parameters of the
test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while
resolving constructor parameters, unless the
<<writing-tests-test-instance-lifecycle, test instance lifecycle>> is set to `PER_CLASS`.
====

[NOTE]
Expand Down Expand Up @@ -723,9 +731,10 @@ include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide]

[NOTE]
====
You may annotate your extension with `{EnableTestScopedConstructorContext}` to make
test-specific data available to your implementation of `interceptTestClassConstructor` and
for a revised scope of the provided `Store` instance.
You may override the
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
`TEST_SCOPED` to make test-specific data available to your implementation of
`interceptTestClassConstructor` and for a revised scope of the provided `Store` instance.
====

[[extensions-test-templates]]
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtensionContext.Store;

/**
* {@code InvocationInterceptor} defines the API for {@link Extension
Expand All @@ -50,17 +51,18 @@
* @see ExtensionContext
*/
@API(status = STABLE, since = "5.10")
public interface InvocationInterceptor extends Extension {
public interface InvocationInterceptor extends TestClassInstanceConstructionParticipatingExtension {

/**
* Intercept the invocation of a test class constructor.
*
* <p>Note that the test class may <em>not</em> have been initialized
* (static initialization) when this method is invoked.
*
* <p>You may annotate your extension with {@link EnableTestScopedConstructorContext}
* to make test-specific data available to your implementation of this method and
* for a revised scope of the provided `Store` instance.
* <p>Extensions may override
* {@link #getExtensionContextScopeDuringTestClassInstanceConstruction} to
* make test-specific data available to the implementation of this method
* and for a revised scope of the provided {@link Store Store} instance.
*
* @param invocation the invocation that is being intercepted; never
* {@code null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@
* an argument for the parameter must be resolved at runtime by a
* {@code ParameterResolver}.
*
* <p>You may annotate your extension with {@link EnableTestScopedConstructorContext}
* to support injecting test specific data into constructor parameters of the test instance.
* The annotation makes JUnit use a test-specific `ExtensionContext` while resolving
* constructor parameters, unless the test class is annotated with
* {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}.
* <p>Extensions may override
* {@link #getExtensionContextScopeDuringTestClassInstanceConstruction} to
* support injecting test specific data into constructor parameters of the test
* class instance. Returning
* {@link ExtensionContextScope#TEST_METHOD TEST_SCOPED} from this method,
* causes a test-specific {@link ExtensionContext} to be used while resolving
* constructor parameters, unless the lifecycle is set to
* {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS}.
*
* <h2>Constructor Requirements</h2>
*
Expand All @@ -51,7 +54,7 @@
* @see TestInstancePreDestroyCallback
*/
@API(status = STABLE, since = "5.0")
public interface ParameterResolver extends Extension {
public interface ParameterResolver extends TestClassInstanceConstructionParticipatingExtension {

/**
* Determine if this resolver supports resolution of an argument for the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2015-2024 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v2.0 which
* accompanies this distribution and is available at
*
* https://www.eclipse.org/legal/epl-v20.html
*/

package org.junit.jupiter.api.extension;

import static org.apiguardian.api.API.Status.DEPRECATED;
import static org.apiguardian.api.API.Status.EXPERIMENTAL;

import org.apiguardian.api.API;
import org.junit.jupiter.api.TestInstance;

/**
* Interface for {@link Extension Extensions} that participate in the
* construction of test class instances.
*
* @since 5.12
* @see InvocationInterceptor#interceptTestClassConstructor
* @see ParameterResolver
* @see TestInstancePreConstructCallback
* @see TestInstancePostProcessor
* @see TestInstanceFactory
*/
@API(status = EXPERIMENTAL, since = "5.12")
public interface TestClassInstanceConstructionParticipatingExtension extends Extension {

/**
* Whether this extension should receive a test-scoped
* {@link ExtensionContext} during the creation of test instances.
*
* <p>If an extension returns
* {@link ExtensionContextScope#TEST_METHOD TEST_SCOPED} from this method,
* the following extension methods will be called with a test-scoped
* {@link ExtensionContext} instead of a class-scoped one, unless the
* {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used:
*
* <ul>
* <li>{@link InvocationInterceptor#interceptTestClassConstructor}</li>
* <li>{@link ParameterResolver} when resolving constructor parameters</li>
* <li>{@link TestInstancePreConstructCallback}</li>
* <li>{@link TestInstancePostProcessor}</li>
* <li>{@link TestInstanceFactory}</li>
* </ul>
*
* <p>In such cases, implementations of these extension callbacks can
* observe the following differences:
*
* <ul>
* <li>{@link ExtensionContext#getElement() getElement()} may refer to the
* test method and {@link ExtensionContext#getTestClass() getTestClass()}
* may refer to a nested test class.
* Use {@link TestInstanceFactoryContext#getTestClass()} to get the class
* under construction.</li>
* <li>{@link ExtensionContext#getTestMethod() getTestMethod()} is no-longer
* empty, unless the test class is annotated with
* {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}.</li>
* <li>If the callback adds a new {@link ExtensionContext.Store.CloseableResource} to the
* {@link ExtensionContext.Store}, the resource is closed just after the instance is
* destroyed.</li>
* <li>The callbacks can now access data previously stored by
* {@link TestTemplateInvocationContext}, unless the test class is annotated
* with {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}.</li>
* </ul>
*
* <p><strong>Note</strong>: The behavior which is enabled by returning
* {@link ExtensionContextScope#TEST_METHOD TEST_SCOPED} from this method
* will become the default in future versions of JUnit. To ensure future
* compatibility, extension implementors are therefore advised to opt in,
* even if they don't require the new functionality.
*
* @implNote There are no guarantees about how often this method is called.
* Therefore, implementations should be idempotent and avoid side
* effects. They may, however, cache the result for performance in
* the {@link ExtensionContext.Store Store} of the supplied
* {@link ExtensionContext}, if necessary.
* @param rootContext the root extension context to allow inspection of
* configuration parameters; never {@code null}
* @since 5.12
*/
@API(status = EXPERIMENTAL, since = "5.12")
default ExtensionContextScope getExtensionContextScopeDuringTestClassInstanceConstruction(
ExtensionContext rootContext) {
return ExtensionContextScope.DEFAULT;
}

/**
* {@code ExtensionContextScope} is used to define the scope of the
* {@link ExtensionContext} passed to an extension during the construction
* of test class instances.
*
* @since 5.12
* @see TestClassInstanceConstructionParticipatingExtension#getExtensionContextScopeDuringTestClassInstanceConstruction
*/
@API(status = EXPERIMENTAL, since = "5.12")
enum ExtensionContextScope {

/**
* The extension should receive an {@link ExtensionContext} scoped to
* the test class.
*
* @deprecated This behavior will be removed from future versions of
* JUnit and {@link #TEST_METHOD} will become the default.
*/
@API(status = DEPRECATED, since = "5.12") //
@Deprecated
DEFAULT,

/**
* The extension should receive an {@link ExtensionContext} scoped to
* the test method, unless the
* {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used.
*/
TEST_METHOD
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@
*/
@FunctionalInterface
@API(status = STABLE, since = "5.7")
public interface TestInstanceFactory extends Extension {
public interface TestInstanceFactory extends TestClassInstanceConstructionParticipatingExtension {

/**
* Callback for creating a test instance for the supplied context.
*
* <p>You may annotate your extension with
* {@link EnableTestScopedConstructorContext @EnableTestScopedConstructorContext}
* for revised handling of {@link CloseableResource CloseableResource} and
* to make test-specific data available to your implementation.
* <p>Extensions may override
* {@link #getExtensionContextScopeDuringTestClassInstanceConstruction} for
* revised handling of {@link CloseableResource CloseableResource} and to
* make test-specific data available to your implementation.
*
* <p><strong>Note</strong>: the {@code ExtensionContext} supplied to a
* {@code TestInstanceFactory} will always return an empty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@
*/
@FunctionalInterface
@API(status = STABLE, since = "5.0")
public interface TestInstancePostProcessor extends Extension {
public interface TestInstancePostProcessor extends TestClassInstanceConstructionParticipatingExtension {

/**
* Callback for post-processing the supplied test instance.
*
* <p>You may annotate your extension with
* {@link EnableTestScopedConstructorContext @EnableTestScopedConstructorContext}
* for revised handling of {@link CloseableResource CloseableResource} and
* to make test-specific data available to your implementation.
* <p>Extensions may override
* {@link #getExtensionContextScopeDuringTestClassInstanceConstruction} for
* revised handling of {@link CloseableResource CloseableResource} and to
* make test-specific data available to your implementation.
*
* <p><strong>Note</strong>: the {@code ExtensionContext} supplied to a
* {@code TestInstancePostProcessor} will always return an empty
Expand Down
Loading