diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInstance.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInstance.java index 37516dd95a18..5b428b8f0515 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInstance.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInstance.java @@ -57,6 +57,9 @@ /** * Enumeration of test instance lifecycle modes. + * + * @see #PER_METHOD + * @see #PER_CLASS */ enum Lifecycle { 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 34fc8d446a70..c78ebf4ee382 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 @@ -70,6 +70,21 @@ public final class Constants { */ public static final String EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME = "junit.jupiter.extensions.autodetection.enabled"; + /** + * Property name used to set the default test instance lifecycle mode: {@value} + * + *

Supported Values

+ * + *

Supported values include names of enum constants defined in + * {@link org.junit.jupiter.api.TestInstance.Lifecycle}, ignoring case. + * + *

If not specified, the default is "per_method" which corresponds to + * {@code @TestInstance(Lifecycle.PER_METHOD)}. + * + * @see org.junit.jupiter.api.TestInstance + */ + public static final String DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME = "junit.jupiter.testinstance.lifecycle.default"; + private Constants() { /* no-op */ } diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java index 977aba296d44..eadc87c4db62 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java @@ -10,6 +10,7 @@ package org.junit.jupiter.engine.descriptor; +import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME; import static org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.findAfterAllMethods; import static org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.findAfterEachMethods; import static org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.findBeforeAllMethods; @@ -21,6 +22,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -43,6 +45,7 @@ import org.junit.platform.commons.util.AnnotationUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestTag; import org.junit.platform.engine.UniqueId; @@ -65,7 +68,8 @@ public class ClassTestDescriptor extends JupiterTestDescriptor { private static final ExecutableInvoker executableInvoker = new ExecutableInvoker(); private final Class testClass; - private final Lifecycle lifecycle; + + private Lifecycle lifecycle; private List beforeAllMethods; private List afterAllMethods; @@ -83,7 +87,6 @@ protected ClassTestDescriptor(UniqueId uniqueId, Function, String> defa defaultDisplayNameGenerator), new ClassSource(testClass)); this.testClass = testClass; - this.lifecycle = getTestInstanceLifecycle(testClass); } // --- TestDescriptor ------------------------------------------------------ @@ -117,6 +120,8 @@ private static String generateDefaultDisplayName(Class testClass) { @Override public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) { + this.lifecycle = getTestInstanceLifecycle(testClass, context.getConfigurationParameters()); + this.beforeAllMethods = findBeforeAllMethods(testClass, this.lifecycle == Lifecycle.PER_METHOD); this.afterAllMethods = findAfterAllMethods(testClass, this.lifecycle == Lifecycle.PER_METHOD); this.beforeEachMethods = findBeforeEachMethods(testClass); @@ -291,12 +296,33 @@ private void invokeMethodInExtensionContext(Method method, ExtensionContext cont executableInvoker.invoke(method, testInstance, context, registry); } - private static TestInstance.Lifecycle getTestInstanceLifecycle(Class testClass) { + private static TestInstance.Lifecycle getTestInstanceLifecycle(Class testClass, + ConfigurationParameters configurationParameters) { + // @formatter:off return AnnotationUtils.findAnnotation(testClass, TestInstance.class) .map(TestInstance::value) - .orElse(Lifecycle.PER_METHOD); + .orElseGet(() -> getDefaultTestInstanceLifecycle(configurationParameters)); // @formatter:on } + private static TestInstance.Lifecycle getDefaultTestInstanceLifecycle( + ConfigurationParameters configurationParameters) { + + Optional optional = configurationParameters.get(DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME); + if (optional.isPresent()) { + try { + String constantName = optional.get().trim().toUpperCase(); + Lifecycle lifecycle = TestInstance.Lifecycle.valueOf(constantName); + // TODO Log info message. + return lifecycle; + } + catch (Exception ex) { + // TODO Log error message. + } + } + + return Lifecycle.PER_METHOD; + } + }