Skip to content

Commit d909371

Browse files
committed
Introduce configuration parameter for default extension context scope
1 parent cee896f commit d909371

File tree

8 files changed

+90
-20
lines changed

8 files changed

+90
-20
lines changed

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.junit.jupiter.api.io.TempDir;
3737
import org.junit.jupiter.api.parallel.Execution;
3838
import org.junit.jupiter.engine.config.JupiterConfiguration;
39+
import org.junit.jupiter.engine.execution.ExtensionContextSupplier;
3940
import org.junit.platform.commons.util.ClassNamePatternFilterUtils;
4041
import org.junit.platform.engine.support.hierarchical.ParallelExecutionConfigurationStrategy;
4142

@@ -369,6 +370,16 @@ public final class Constants {
369370
@API(status = EXPERIMENTAL, since = "5.10")
370371
public static final String DEFAULT_TEMP_DIR_FACTORY_PROPERTY_NAME = TempDir.DEFAULT_FACTORY_PROPERTY_NAME;
371372

373+
/**
374+
* Property name used to set the default extension context scope for
375+
* extensions that participate in test class instance construction: {@value}
376+
*
377+
* @since 5.12
378+
* @see org.junit.jupiter.api.extension.TestClassInstanceConstructionParticipatingExtension
379+
*/
380+
@API(status = EXPERIMENTAL, since = "5.12")
381+
public static final String DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME = ExtensionContextSupplier.DEFAULT_SCOPE_PROPERTY_NAME;
382+
372383
private Constants() {
373384
/* no-op */
374385
}

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.junit.jupiter.api.MethodOrderer;
2727
import org.junit.jupiter.api.TestInstance;
2828
import org.junit.jupiter.api.extension.ExecutionCondition;
29+
import org.junit.jupiter.api.extension.TestClassInstanceConstructionParticipatingExtension.ExtensionContextScope;
2930
import org.junit.jupiter.api.io.CleanupMode;
3031
import org.junit.jupiter.api.io.TempDirFactory;
3132
import org.junit.jupiter.api.parallel.ExecutionMode;
@@ -58,71 +59,77 @@ public <T> Optional<T> getRawConfigurationParameter(String key, Function<String,
5859
@Override
5960
public boolean isParallelExecutionEnabled() {
6061
return (boolean) cache.computeIfAbsent(PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME,
61-
key -> delegate.isParallelExecutionEnabled());
62+
__ -> delegate.isParallelExecutionEnabled());
6263
}
6364

6465
@Override
6566
public boolean isExtensionAutoDetectionEnabled() {
6667
return (boolean) cache.computeIfAbsent(EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME,
67-
key -> delegate.isExtensionAutoDetectionEnabled());
68+
__ -> delegate.isExtensionAutoDetectionEnabled());
6869
}
6970

7071
@Override
7172
public ExecutionMode getDefaultExecutionMode() {
7273
return (ExecutionMode) cache.computeIfAbsent(DEFAULT_EXECUTION_MODE_PROPERTY_NAME,
73-
key -> delegate.getDefaultExecutionMode());
74+
__ -> delegate.getDefaultExecutionMode());
7475
}
7576

7677
@Override
7778
public ExecutionMode getDefaultClassesExecutionMode() {
7879
return (ExecutionMode) cache.computeIfAbsent(DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME,
79-
key -> delegate.getDefaultClassesExecutionMode());
80+
__ -> delegate.getDefaultClassesExecutionMode());
8081
}
8182

8283
@Override
8384
public TestInstance.Lifecycle getDefaultTestInstanceLifecycle() {
8485
return (TestInstance.Lifecycle) cache.computeIfAbsent(DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME,
85-
key -> delegate.getDefaultTestInstanceLifecycle());
86+
__ -> delegate.getDefaultTestInstanceLifecycle());
8687
}
8788

8889
@SuppressWarnings("unchecked")
8990
@Override
9091
public Predicate<ExecutionCondition> getExecutionConditionFilter() {
9192
return (Predicate<ExecutionCondition>) cache.computeIfAbsent(DEACTIVATE_CONDITIONS_PATTERN_PROPERTY_NAME,
92-
key -> delegate.getExecutionConditionFilter());
93+
__ -> delegate.getExecutionConditionFilter());
9394
}
9495

9596
@Override
9697
public DisplayNameGenerator getDefaultDisplayNameGenerator() {
9798
return (DisplayNameGenerator) cache.computeIfAbsent(DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME,
98-
key -> delegate.getDefaultDisplayNameGenerator());
99+
__ -> delegate.getDefaultDisplayNameGenerator());
99100
}
100101

101102
@SuppressWarnings("unchecked")
102103
@Override
103104
public Optional<MethodOrderer> getDefaultTestMethodOrderer() {
104105
return (Optional<MethodOrderer>) cache.computeIfAbsent(DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME,
105-
key -> delegate.getDefaultTestMethodOrderer());
106+
__ -> delegate.getDefaultTestMethodOrderer());
106107
}
107108

108109
@SuppressWarnings("unchecked")
109110
@Override
110111
public Optional<ClassOrderer> getDefaultTestClassOrderer() {
111112
return (Optional<ClassOrderer>) cache.computeIfAbsent(DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME,
112-
key -> delegate.getDefaultTestClassOrderer());
113+
__ -> delegate.getDefaultTestClassOrderer());
113114
}
114115

115116
@Override
116117
public CleanupMode getDefaultTempDirCleanupMode() {
117118
return (CleanupMode) cache.computeIfAbsent(DEFAULT_CLEANUP_MODE_PROPERTY_NAME,
118-
key -> delegate.getDefaultTempDirCleanupMode());
119+
__ -> delegate.getDefaultTempDirCleanupMode());
119120
}
120121

121122
@SuppressWarnings("unchecked")
122123
@Override
123124
public Supplier<TempDirFactory> getDefaultTempDirFactorySupplier() {
124125
return (Supplier<TempDirFactory>) cache.computeIfAbsent(DEFAULT_FACTORY_PROPERTY_NAME,
125-
key -> delegate.getDefaultTempDirFactorySupplier());
126+
__ -> delegate.getDefaultTempDirFactorySupplier());
126127
}
127128

129+
@Override
130+
public ExtensionContextScope getDefaultTestClassInstanceConstructionExtensionContextScope() {
131+
return (ExtensionContextScope) cache.computeIfAbsent(
132+
DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME,
133+
__ -> delegate.getDefaultTestClassInstanceConstructionExtensionContextScope());
134+
}
128135
}

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.junit.jupiter.api.MethodOrderer;
2727
import org.junit.jupiter.api.TestInstance.Lifecycle;
2828
import org.junit.jupiter.api.extension.ExecutionCondition;
29+
import org.junit.jupiter.api.extension.TestClassInstanceConstructionParticipatingExtension.ExtensionContextScope;
2930
import org.junit.jupiter.api.io.CleanupMode;
3031
import org.junit.jupiter.api.io.TempDirFactory;
3132
import org.junit.jupiter.api.parallel.ExecutionMode;
@@ -62,6 +63,9 @@ public class DefaultJupiterConfiguration implements JupiterConfiguration {
6263
private static final InstantiatingConfigurationParameterConverter<TempDirFactory> tempDirFactoryConverter = //
6364
new InstantiatingConfigurationParameterConverter<>(TempDirFactory.class, "temp dir factory");
6465

66+
private static final EnumConfigurationParameterConverter<ExtensionContextScope> extensionContextScopeConverter = //
67+
new EnumConfigurationParameterConverter<>(ExtensionContextScope.class, "extension context scope");
68+
6569
private final ConfigurationParameters configurationParameters;
6670

6771
public DefaultJupiterConfiguration(ConfigurationParameters configurationParameters) {
@@ -141,4 +145,11 @@ public Supplier<TempDirFactory> getDefaultTempDirFactorySupplier() {
141145
return () -> supplier.get().orElse(TempDirFactory.Standard.INSTANCE);
142146
}
143147

148+
@SuppressWarnings("deprecation")
149+
@Override
150+
public ExtensionContextScope getDefaultTestClassInstanceConstructionExtensionContextScope() {
151+
return extensionContextScopeConverter.get(configurationParameters,
152+
DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME,
153+
ExtensionContextScope.DEFAULT);
154+
}
144155
}

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
import org.junit.jupiter.api.MethodOrderer;
2424
import org.junit.jupiter.api.TestInstance;
2525
import org.junit.jupiter.api.extension.ExecutionCondition;
26+
import org.junit.jupiter.api.extension.TestClassInstanceConstructionParticipatingExtension.ExtensionContextScope;
2627
import org.junit.jupiter.api.io.CleanupMode;
2728
import org.junit.jupiter.api.io.TempDirFactory;
2829
import org.junit.jupiter.api.parallel.Execution;
2930
import org.junit.jupiter.api.parallel.ExecutionMode;
31+
import org.junit.jupiter.engine.execution.ExtensionContextSupplier;
3032

3133
/**
3234
* @since 5.4
@@ -42,7 +44,8 @@ public interface JupiterConfiguration {
4244
String DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME = TestInstance.Lifecycle.DEFAULT_LIFECYCLE_PROPERTY_NAME;
4345
String DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME = DisplayNameGenerator.DEFAULT_GENERATOR_PROPERTY_NAME;
4446
String DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME = MethodOrderer.DEFAULT_ORDER_PROPERTY_NAME;
45-
String DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME = ClassOrderer.DEFAULT_ORDER_PROPERTY_NAME;
47+
String DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME = ClassOrderer.DEFAULT_ORDER_PROPERTY_NAME;;
48+
String DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME = ExtensionContextSupplier.DEFAULT_SCOPE_PROPERTY_NAME;
4649

4750
Optional<String> getRawConfigurationParameter(String key);
4851

@@ -70,4 +73,6 @@ public interface JupiterConfiguration {
7073

7174
Supplier<TempDirFactory> getDefaultTempDirFactorySupplier();
7275

76+
ExtensionContextScope getDefaultTestClassInstanceConstructionExtensionContextScope();
77+
7378
}

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ private TestInstances instantiateAndPostProcessTestInstance(JupiterEngineExecuti
288288
JupiterEngineExecutionContext context) {
289289

290290
ExtensionContextSupplier extensionContext = ExtensionContextSupplier.create(context.getExtensionContext(),
291-
ourExtensionContext);
291+
ourExtensionContext, configuration);
292292
TestInstances instances = instantiateTestClass(parentExecutionContext, extensionContext, registry, context);
293293
context.getThrowableCollector().execute(() -> {
294294
invokeTestInstancePostProcessors(instances.getInnermostInstance(), registry, extensionContext);

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.apiguardian.api.API;
1717
import org.junit.jupiter.api.extension.ExtensionContext;
1818
import org.junit.jupiter.api.extension.TestClassInstanceConstructionParticipatingExtension;
19+
import org.junit.jupiter.engine.config.JupiterConfiguration;
1920

2021
/**
2122
* Container of two instances of {@link ExtensionContext} to simplify the legacy for
@@ -28,9 +29,12 @@
2829
@API(status = INTERNAL, since = "5.12")
2930
public interface ExtensionContextSupplier {
3031

32+
String DEFAULT_SCOPE_PROPERTY_NAME = "junit.jupiter.extensions.testClassInstanceConstruction.extensionContextScope.default";
33+
3134
static ExtensionContextSupplier create(ExtensionContext currentExtensionContext,
32-
ExtensionContext legacyExtensionContext) {
33-
if (currentExtensionContext == legacyExtensionContext) {
35+
ExtensionContext legacyExtensionContext, JupiterConfiguration configuration) {
36+
if (currentExtensionContext == legacyExtensionContext
37+
|| configuration.getDefaultTestClassInstanceConstructionExtensionContextScope() == TEST_METHOD) {
3438
return __ -> currentExtensionContext;
3539
}
3640
return new ScopeBasedExtensionContextSupplier(currentExtensionContext, legacyExtensionContext);

jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,8 @@ void invokeMethod() {
3131

3232
@Override
3333
<T> T invokeConstructor(Constructor<T> constructor, Object outerInstance) {
34-
ExtensionContextSupplier context = ExtensionContextSupplier.create(extensionContext, extensionContext);
35-
return newInvoker().invoke(constructor, Optional.ofNullable(outerInstance), context, extensionRegistry,
36-
passthroughInterceptor());
34+
return newInvoker().invoke(constructor, Optional.ofNullable(outerInstance), __ -> extensionContext,
35+
extensionRegistry, passthroughInterceptor());
3736
}
3837

3938
private InterceptingExecutableInvoker newInvoker() {

jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
1616
import static org.junit.jupiter.api.extension.TestClassInstanceConstructionParticipatingExtension.ExtensionContextScope.TEST_METHOD;
1717
import static org.junit.platform.commons.util.ClassUtils.nullSafeToString;
18+
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
19+
import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
1820
import static org.junit.platform.testkit.engine.EventConditions.container;
1921
import static org.junit.platform.testkit.engine.EventConditions.engine;
2022
import static org.junit.platform.testkit.engine.EventConditions.event;
@@ -44,6 +46,7 @@
4446
import org.junit.jupiter.api.extension.TestInstanceFactoryContext;
4547
import org.junit.jupiter.api.extension.TestInstantiationException;
4648
import org.junit.jupiter.engine.AbstractJupiterTestEngineTests;
49+
import org.junit.jupiter.engine.Constants;
4750
import org.junit.platform.commons.support.ReflectionSupport;
4851
import org.junit.platform.commons.test.TestClassLoader;
4952
import org.junit.platform.testkit.engine.EngineExecutionResults;
@@ -429,6 +432,36 @@ void instanceFactoryWithLegacyContext() {
429432
// @formatter:on
430433
}
431434

435+
@Test
436+
void instanceFactoryWithLegacyContextAndChangedDefaultScope() {
437+
var executionResults = executeTests(request() //
438+
.selectors(selectClass(LegacyContextTestCase.class)) //
439+
.configurationParameter(
440+
Constants.DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME,
441+
TEST_METHOD.name()));
442+
443+
assertEquals(3, executionResults.testEvents().started().count(), "# tests started");
444+
assertEquals(3, executionResults.testEvents().succeeded().count(), "# tests succeeded");
445+
446+
// @formatter:off
447+
assertThat(callSequence).containsExactly(
448+
"LegacyInstanceFactory instantiated: LegacyContextTestCase",
449+
"outerTest",
450+
"close LegacyContextTestCase",
451+
"LegacyInstanceFactory instantiated: LegacyContextTestCase",
452+
"LegacyInstanceFactory instantiated: InnerTestCase",
453+
"innerTest1",
454+
"close InnerTestCase",
455+
"close LegacyContextTestCase",
456+
"LegacyInstanceFactory instantiated: LegacyContextTestCase",
457+
"LegacyInstanceFactory instantiated: InnerTestCase",
458+
"innerTest2",
459+
"close InnerTestCase",
460+
"close LegacyContextTestCase"
461+
);
462+
// @formatter:on
463+
}
464+
432465
// -------------------------------------------------------------------------
433466

434467
@ExtendWith({ FooInstanceFactory.class, BarInstanceFactory.class })
@@ -784,8 +817,8 @@ public Object createTestInstance(TestInstanceFactoryContext factoryContext, Exte
784817
}
785818
}
786819

787-
private static boolean instantiated(Class<? extends TestInstanceFactory> factoryClass, Class<?> testClass) {
788-
return callSequence.add(factoryClass.getSimpleName() + " instantiated: " + testClass.getSimpleName());
820+
private static void instantiated(Class<? extends TestInstanceFactory> factoryClass, Class<?> testClass) {
821+
callSequence.add(factoryClass.getSimpleName() + " instantiated: " + testClass.getSimpleName());
789822
}
790823

791824
}

0 commit comments

Comments
 (0)