diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationAwareExtension.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationAwareExtension.java
index 48c327705413..5308f65cb516 100644
--- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationAwareExtension.java
+++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationAwareExtension.java
@@ -106,10 +106,16 @@ enum ExtensionContextScope {
/**
* The extension should receive an {@link ExtensionContext} scoped to
- * the test class.
+ * in the default scope.
+ *
+ *
The default scope is determined by the configuration parameter
+ * {@link #DEFAULT_SCOPE_PROPERTY_NAME}. If not specified, extensions
+ * will 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.
+ *
+ * @see #DEFAULT_SCOPE_PROPERTY_NAME
*/
@API(status = DEPRECATED, since = "5.12") //
@Deprecated
@@ -120,7 +126,19 @@ enum ExtensionContextScope {
* the test method, unless the
* {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used.
*/
- TEST_METHOD
+ TEST_METHOD;
+
+ /**
+ * Property name used to set the default extension context scope: {@value}
+ *
+ *
Supported Values
+ *
+ * Supported values include names of enum constants defined in this
+ * class, ignoring case.
+ *
+ * @see #DEFAULT
+ */
+ public static final String DEFAULT_SCOPE_PROPERTY_NAME = "junit.jupiter.extensions.testInstantiation.extensionContextScope.default";
}
}
diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java
index 1b0636f18d10..2f64dd866cd2 100644
--- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java
+++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java
@@ -33,6 +33,7 @@
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.Timeout;
+import org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.engine.config.JupiterConfiguration;
@@ -369,6 +370,16 @@ public final class Constants {
@API(status = EXPERIMENTAL, since = "5.10")
public static final String DEFAULT_TEMP_DIR_FACTORY_PROPERTY_NAME = TempDir.DEFAULT_FACTORY_PROPERTY_NAME;
+ /**
+ * Property name used to set the default extension context scope for
+ * extensions that participate in test instantiation: {@value}
+ *
+ * @since 5.12
+ * @see org.junit.jupiter.api.extension.TestInstantiationAwareExtension
+ */
+ @API(status = EXPERIMENTAL, since = "5.12")
+ public static final String DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME = ExtensionContextScope.DEFAULT_SCOPE_PROPERTY_NAME;
+
private Constants() {
/* no-op */
}
diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java
index 1280c4b12a11..3082830d2146 100644
--- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java
+++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java
@@ -26,6 +26,7 @@
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExecutionCondition;
+import org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope;
import org.junit.jupiter.api.io.CleanupMode;
import org.junit.jupiter.api.io.TempDirFactory;
import org.junit.jupiter.api.parallel.ExecutionMode;
@@ -58,71 +59,77 @@ public Optional getRawConfigurationParameter(String key, Function delegate.isParallelExecutionEnabled());
+ __ -> delegate.isParallelExecutionEnabled());
}
@Override
public boolean isExtensionAutoDetectionEnabled() {
return (boolean) cache.computeIfAbsent(EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME,
- key -> delegate.isExtensionAutoDetectionEnabled());
+ __ -> delegate.isExtensionAutoDetectionEnabled());
}
@Override
public ExecutionMode getDefaultExecutionMode() {
return (ExecutionMode) cache.computeIfAbsent(DEFAULT_EXECUTION_MODE_PROPERTY_NAME,
- key -> delegate.getDefaultExecutionMode());
+ __ -> delegate.getDefaultExecutionMode());
}
@Override
public ExecutionMode getDefaultClassesExecutionMode() {
return (ExecutionMode) cache.computeIfAbsent(DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME,
- key -> delegate.getDefaultClassesExecutionMode());
+ __ -> delegate.getDefaultClassesExecutionMode());
}
@Override
public TestInstance.Lifecycle getDefaultTestInstanceLifecycle() {
return (TestInstance.Lifecycle) cache.computeIfAbsent(DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME,
- key -> delegate.getDefaultTestInstanceLifecycle());
+ __ -> delegate.getDefaultTestInstanceLifecycle());
}
@SuppressWarnings("unchecked")
@Override
public Predicate getExecutionConditionFilter() {
return (Predicate) cache.computeIfAbsent(DEACTIVATE_CONDITIONS_PATTERN_PROPERTY_NAME,
- key -> delegate.getExecutionConditionFilter());
+ __ -> delegate.getExecutionConditionFilter());
}
@Override
public DisplayNameGenerator getDefaultDisplayNameGenerator() {
return (DisplayNameGenerator) cache.computeIfAbsent(DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME,
- key -> delegate.getDefaultDisplayNameGenerator());
+ __ -> delegate.getDefaultDisplayNameGenerator());
}
@SuppressWarnings("unchecked")
@Override
public Optional getDefaultTestMethodOrderer() {
return (Optional) cache.computeIfAbsent(DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME,
- key -> delegate.getDefaultTestMethodOrderer());
+ __ -> delegate.getDefaultTestMethodOrderer());
}
@SuppressWarnings("unchecked")
@Override
public Optional getDefaultTestClassOrderer() {
return (Optional) cache.computeIfAbsent(DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME,
- key -> delegate.getDefaultTestClassOrderer());
+ __ -> delegate.getDefaultTestClassOrderer());
}
@Override
public CleanupMode getDefaultTempDirCleanupMode() {
return (CleanupMode) cache.computeIfAbsent(DEFAULT_CLEANUP_MODE_PROPERTY_NAME,
- key -> delegate.getDefaultTempDirCleanupMode());
+ __ -> delegate.getDefaultTempDirCleanupMode());
}
@SuppressWarnings("unchecked")
@Override
public Supplier getDefaultTempDirFactorySupplier() {
return (Supplier) cache.computeIfAbsent(DEFAULT_FACTORY_PROPERTY_NAME,
- key -> delegate.getDefaultTempDirFactorySupplier());
+ __ -> delegate.getDefaultTempDirFactorySupplier());
}
+ @Override
+ public ExtensionContextScope getDefaultTestInstantiationExtensionContextScope() {
+ return (ExtensionContextScope) cache.computeIfAbsent(
+ DEFAULT_TEST_INSTANTIATION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME,
+ __ -> delegate.getDefaultTestInstantiationExtensionContextScope());
+ }
}
diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java
index 83ef7592534f..1057ab563b1f 100644
--- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java
+++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java
@@ -26,6 +26,7 @@
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExecutionCondition;
+import org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope;
import org.junit.jupiter.api.io.CleanupMode;
import org.junit.jupiter.api.io.TempDirFactory;
import org.junit.jupiter.api.parallel.ExecutionMode;
@@ -62,6 +63,9 @@ public class DefaultJupiterConfiguration implements JupiterConfiguration {
private static final InstantiatingConfigurationParameterConverter tempDirFactoryConverter = //
new InstantiatingConfigurationParameterConverter<>(TempDirFactory.class, "temp dir factory");
+ private static final EnumConfigurationParameterConverter extensionContextScopeConverter = //
+ new EnumConfigurationParameterConverter<>(ExtensionContextScope.class, "extension context scope");
+
private final ConfigurationParameters configurationParameters;
public DefaultJupiterConfiguration(ConfigurationParameters configurationParameters) {
@@ -141,4 +145,10 @@ public Supplier getDefaultTempDirFactorySupplier() {
return () -> supplier.get().orElse(TempDirFactory.Standard.INSTANCE);
}
+ @SuppressWarnings("deprecation")
+ @Override
+ public ExtensionContextScope getDefaultTestInstantiationExtensionContextScope() {
+ return extensionContextScopeConverter.get(configurationParameters,
+ DEFAULT_TEST_INSTANTIATION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME, ExtensionContextScope.DEFAULT);
+ }
}
diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java
index 7a90072363d2..c695e7e4b10b 100644
--- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java
+++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java
@@ -23,6 +23,7 @@
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExecutionCondition;
+import org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope;
import org.junit.jupiter.api.io.CleanupMode;
import org.junit.jupiter.api.io.TempDirFactory;
import org.junit.jupiter.api.parallel.Execution;
@@ -42,7 +43,8 @@ public interface JupiterConfiguration {
String DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME = TestInstance.Lifecycle.DEFAULT_LIFECYCLE_PROPERTY_NAME;
String DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME = DisplayNameGenerator.DEFAULT_GENERATOR_PROPERTY_NAME;
String DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME = MethodOrderer.DEFAULT_ORDER_PROPERTY_NAME;
- String DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME = ClassOrderer.DEFAULT_ORDER_PROPERTY_NAME;
+ String DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME = ClassOrderer.DEFAULT_ORDER_PROPERTY_NAME;;
+ String DEFAULT_TEST_INSTANTIATION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME = ExtensionContextScope.DEFAULT_SCOPE_PROPERTY_NAME;
Optional getRawConfigurationParameter(String key);
@@ -70,4 +72,6 @@ public interface JupiterConfiguration {
Supplier getDefaultTempDirFactorySupplier();
+ ExtensionContextScope getDefaultTestInstantiationExtensionContextScope();
+
}
diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java
index 69ad2ee520d0..ee53adcb2500 100644
--- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java
+++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java
@@ -288,7 +288,7 @@ private TestInstances instantiateAndPostProcessTestInstance(JupiterEngineExecuti
JupiterEngineExecutionContext context) {
ExtensionContextSupplier extensionContext = ExtensionContextSupplier.create(context.getExtensionContext(),
- ourExtensionContext);
+ ourExtensionContext, configuration);
TestInstances instances = instantiateTestClass(parentExecutionContext, extensionContext, registry, context);
context.getThrowableCollector().execute(() -> {
invokeTestInstancePostProcessors(instances.getInnermostInstance(), registry, extensionContext);
diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java
index 9b911c86a626..84c172765b93 100644
--- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java
+++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java
@@ -16,6 +16,7 @@
import org.apiguardian.api.API;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestInstantiationAwareExtension;
+import org.junit.jupiter.engine.config.JupiterConfiguration;
/**
* Container of two instances of {@link ExtensionContext} to simplify the legacy for
@@ -29,8 +30,9 @@
public interface ExtensionContextSupplier {
static ExtensionContextSupplier create(ExtensionContext currentExtensionContext,
- ExtensionContext legacyExtensionContext) {
- if (currentExtensionContext == legacyExtensionContext) {
+ ExtensionContext legacyExtensionContext, JupiterConfiguration configuration) {
+ if (currentExtensionContext == legacyExtensionContext
+ || configuration.getDefaultTestInstantiationExtensionContextScope() == TEST_METHOD) {
return __ -> currentExtensionContext;
}
return new ScopeBasedExtensionContextSupplier(currentExtensionContext, legacyExtensionContext);
diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java
index aea972a34978..6de1cd4935eb 100644
--- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java
+++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java
@@ -31,9 +31,8 @@ void invokeMethod() {
@Override
T invokeConstructor(Constructor constructor, Object outerInstance) {
- ExtensionContextSupplier context = ExtensionContextSupplier.create(extensionContext, extensionContext);
- return newInvoker().invoke(constructor, Optional.ofNullable(outerInstance), context, extensionRegistry,
- passthroughInterceptor());
+ return newInvoker().invoke(constructor, Optional.ofNullable(outerInstance), __ -> extensionContext,
+ extensionRegistry, passthroughInterceptor());
}
private InterceptingExecutableInvoker newInvoker() {
diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java
index 15a280b5683c..1549260f0007 100644
--- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java
+++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java
@@ -15,6 +15,8 @@
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
import static org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope.TEST_METHOD;
import static org.junit.platform.commons.util.ClassUtils.nullSafeToString;
+import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
+import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
import static org.junit.platform.testkit.engine.EventConditions.container;
import static org.junit.platform.testkit.engine.EventConditions.engine;
import static org.junit.platform.testkit.engine.EventConditions.event;
@@ -44,6 +46,7 @@
import org.junit.jupiter.api.extension.TestInstanceFactoryContext;
import org.junit.jupiter.api.extension.TestInstantiationException;
import org.junit.jupiter.engine.AbstractJupiterTestEngineTests;
+import org.junit.jupiter.engine.Constants;
import org.junit.platform.commons.support.ReflectionSupport;
import org.junit.platform.commons.test.TestClassLoader;
import org.junit.platform.testkit.engine.EngineExecutionResults;
@@ -429,6 +432,36 @@ void instanceFactoryWithLegacyContext() {
// @formatter:on
}
+ @Test
+ void instanceFactoryWithLegacyContextAndChangedDefaultScope() {
+ var executionResults = executeTests(request() //
+ .selectors(selectClass(LegacyContextTestCase.class)) //
+ .configurationParameter(
+ Constants.DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME,
+ TEST_METHOD.name()));
+
+ assertEquals(3, executionResults.testEvents().started().count(), "# tests started");
+ assertEquals(3, executionResults.testEvents().succeeded().count(), "# tests succeeded");
+
+ // @formatter:off
+ assertThat(callSequence).containsExactly(
+ "LegacyInstanceFactory instantiated: LegacyContextTestCase",
+ "outerTest",
+ "close LegacyContextTestCase",
+ "LegacyInstanceFactory instantiated: LegacyContextTestCase",
+ "LegacyInstanceFactory instantiated: InnerTestCase",
+ "innerTest1",
+ "close InnerTestCase",
+ "close LegacyContextTestCase",
+ "LegacyInstanceFactory instantiated: LegacyContextTestCase",
+ "LegacyInstanceFactory instantiated: InnerTestCase",
+ "innerTest2",
+ "close InnerTestCase",
+ "close LegacyContextTestCase"
+ );
+ // @formatter:on
+ }
+
// -------------------------------------------------------------------------
@SuppressWarnings("JUnitMalformedDeclaration")
@@ -797,8 +830,8 @@ public Object createTestInstance(TestInstanceFactoryContext factoryContext, Exte
}
}
- private static boolean instantiated(Class extends TestInstanceFactory> factoryClass, Class> testClass) {
- return callSequence.add(factoryClass.getSimpleName() + " instantiated: " + testClass.getSimpleName());
+ private static void instantiated(Class extends TestInstanceFactory> factoryClass, Class> testClass) {
+ callSequence.add(factoryClass.getSimpleName() + " instantiated: " + testClass.getSimpleName());
}
}