Skip to content

Commit

Permalink
Introduce configuration parameter for default extension context scope
Browse files Browse the repository at this point in the history
  • Loading branch information
marcphilipp committed Oct 11, 2024
1 parent 596907c commit 1e81cbe
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.engine.config.JupiterConfiguration;
import org.junit.jupiter.engine.execution.ExtensionContextSupplier;
import org.junit.platform.commons.util.ClassNamePatternFilterUtils;
import org.junit.platform.engine.support.hierarchical.ParallelExecutionConfigurationStrategy;

Expand Down Expand Up @@ -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 class instance construction: {@value}
*
* @since 5.12
* @see org.junit.jupiter.api.extension.TestClassInstanceConstructionParticipatingExtension
*/
@API(status = EXPERIMENTAL, since = "5.12")
public static final String DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME = ExtensionContextSupplier.DEFAULT_SCOPE_PROPERTY_NAME;

private Constants() {
/* no-op */
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -58,71 +59,77 @@ public <T> Optional<T> getRawConfigurationParameter(String key, Function<String,
@Override
public boolean isParallelExecutionEnabled() {
return (boolean) cache.computeIfAbsent(PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME,
key -> 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<ExecutionCondition> getExecutionConditionFilter() {
return (Predicate<ExecutionCondition>) 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<MethodOrderer> getDefaultTestMethodOrderer() {
return (Optional<MethodOrderer>) cache.computeIfAbsent(DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME,
key -> delegate.getDefaultTestMethodOrderer());
__ -> delegate.getDefaultTestMethodOrderer());
}

@SuppressWarnings("unchecked")
@Override
public Optional<ClassOrderer> getDefaultTestClassOrderer() {
return (Optional<ClassOrderer>) 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<TempDirFactory> getDefaultTempDirFactorySupplier() {
return (Supplier<TempDirFactory>) cache.computeIfAbsent(DEFAULT_FACTORY_PROPERTY_NAME,
key -> delegate.getDefaultTempDirFactorySupplier());
__ -> delegate.getDefaultTempDirFactorySupplier());
}

@Override
public ExtensionContextScope getDefaultTestClassInstanceConstructionExtensionContextScope() {
return (ExtensionContextScope) cache.computeIfAbsent(
DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME,
__ -> delegate.getDefaultTestClassInstanceConstructionExtensionContextScope());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -62,6 +63,9 @@ public class DefaultJupiterConfiguration implements JupiterConfiguration {
private static final InstantiatingConfigurationParameterConverter<TempDirFactory> tempDirFactoryConverter = //
new InstantiatingConfigurationParameterConverter<>(TempDirFactory.class, "temp dir factory");

private static final EnumConfigurationParameterConverter<ExtensionContextScope> extensionContextScopeConverter = //
new EnumConfigurationParameterConverter<>(ExtensionContextScope.class, "extension context scope");

private final ConfigurationParameters configurationParameters;

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

@SuppressWarnings("deprecation")
@Override
public ExtensionContextScope getDefaultTestClassInstanceConstructionExtensionContextScope() {
return extensionContextScopeConverter.get(configurationParameters,
DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME,
ExtensionContextScope.DEFAULT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
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;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.junit.jupiter.engine.execution.ExtensionContextSupplier;

/**
* @since 5.4
Expand All @@ -42,7 +44,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_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME = ExtensionContextSupplier.DEFAULT_SCOPE_PROPERTY_NAME;

Optional<String> getRawConfigurationParameter(String key);

Expand Down Expand Up @@ -70,4 +73,6 @@ public interface JupiterConfiguration {

Supplier<TempDirFactory> getDefaultTempDirFactorySupplier();

ExtensionContextScope getDefaultTestClassInstanceConstructionExtensionContextScope();

}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -28,9 +29,12 @@
@API(status = INTERNAL, since = "5.12")
public interface ExtensionContextSupplier {

String DEFAULT_SCOPE_PROPERTY_NAME = "junit.jupiter.extensions.testClassInstanceConstruction.extensionContextScope.default";

static ExtensionContextSupplier create(ExtensionContext currentExtensionContext,
ExtensionContext legacyExtensionContext) {
if (currentExtensionContext == legacyExtensionContext) {
ExtensionContext legacyExtensionContext, JupiterConfiguration configuration) {
if (currentExtensionContext == legacyExtensionContext
|| configuration.getDefaultTestClassInstanceConstructionExtensionContextScope() == TEST_METHOD) {
return __ -> currentExtensionContext;
}
return new ScopeBasedExtensionContextSupplier(currentExtensionContext, legacyExtensionContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ void invokeMethod() {

@Override
<T> T invokeConstructor(Constructor<T> 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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
}

// -------------------------------------------------------------------------

@ExtendWith({ FooInstanceFactory.class, BarInstanceFactory.class })
Expand Down Expand Up @@ -782,8 +815,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());
}

}

0 comments on commit 1e81cbe

Please sign in to comment.