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 d46432ed4fe5..e26750af9882 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 @@ -21,8 +21,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Function; import org.junit.jupiter.api.TestInstance; @@ -136,15 +136,8 @@ public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext conte ClassBasedContainerExtensionContext containerExtensionContext = new ClassBasedContainerExtensionContext( context.getExtensionContext(), context.getExecutionListener(), this); - // Reuse TestInstanceProvider for potential transparent instance caching. TestInstanceProvider testInstanceProvider = testInstanceProvider(context, registry, containerExtensionContext); - // Eagerly load test instance for BeforeAllCallbacks, if necessary, - // and store the instance in the ContainerExtensionContext. - Object testInstance = (this.lifecycle == Lifecycle.PER_CLASS - ? testInstanceProvider.getTestInstance(Optional.empty()) : null); - containerExtensionContext.setTestInstance(testInstance); - // @formatter:off return context.extend() .withTestInstanceProvider(testInstanceProvider) @@ -185,39 +178,37 @@ public void after(JupiterEngineExecutionContext context) throws Exception { context.getThrowableCollector().assertEmpty(); } - protected TestInstanceProvider testInstanceProvider(JupiterEngineExecutionContext parentExecutionContext, - ExtensionRegistry registry, ExtensionContext extensionContext) { - - TestInstanceProvider testInstanceProvider = childExtensionRegistry -> { - Constructor constructor = ReflectionUtils.getDeclaredConstructor(this.testClass); - Object instance = executableInvoker.invoke(constructor, extensionContext, - childExtensionRegistry.orElse(registry)); - - updateTestInstanceInContainerExtensionContext(extensionContext, instance); - invokeTestInstancePostProcessors(instance, childExtensionRegistry.orElse(registry), extensionContext); - - return instance; - }; + private TestInstanceProvider testInstanceProvider(JupiterEngineExecutionContext parentExecutionContext, + ExtensionRegistry registry, ClassBasedContainerExtensionContext extensionContext) { + if (this.lifecycle == Lifecycle.PER_CLASS) { + // Eagerly load test instance for BeforeAllCallbacks, if necessary, + // and store the instance in the ContainerExtensionContext. + Object instance = instantiateAndPostProcessTestInstance(parentExecutionContext, extensionContext, registry, + extensionContext::setTestInstance); + return childRegistry -> instance; + } + return childRegistry -> instantiateAndPostProcessTestInstance(parentExecutionContext, extensionContext, + childRegistry.orElse(registry), instance -> { + // no extension context update required + }); + } - return new LifecycleAwareDelegatingTestInstanceProvider(testInstanceProvider, this.lifecycle); + private Object instantiateAndPostProcessTestInstance(JupiterEngineExecutionContext context, + ExtensionContext extensionContext, ExtensionRegistry registry, Consumer testInstanceConsumer) { + Object instance = instantiateTestClass(context, registry, extensionContext); + testInstanceConsumer.accept(instance); + invokeTestInstancePostProcessors(instance, registry, extensionContext); + return instance; } - /** - * Potentially update the test instance in the provided {@link ExtensionContext}, - * if it is an instance of {@link ClassBasedContainerExtensionContext} and if the - * test instance lifecycle is {@link Lifecycle#PER_CLASS}. - * - *

Intended to be invoked prior to {@link #invokeTestInstancePostProcessors}. - */ - protected void updateTestInstanceInContainerExtensionContext(ExtensionContext extensionContext, Object instance) { - if (this.lifecycle == Lifecycle.PER_CLASS && extensionContext instanceof ClassBasedContainerExtensionContext) { - ((ClassBasedContainerExtensionContext) extensionContext).setTestInstance(instance); - } + protected Object instantiateTestClass(JupiterEngineExecutionContext parentExecutionContext, + ExtensionRegistry registry, ExtensionContext extensionContext) { + Constructor constructor = ReflectionUtils.getDeclaredConstructor(this.testClass); + return executableInvoker.invoke(constructor, extensionContext, registry); } - protected void invokeTestInstancePostProcessors(Object instance, ExtensionRegistry registry, + private void invokeTestInstancePostProcessors(Object instance, ExtensionRegistry registry, ExtensionContext context) { - registry.stream(TestInstancePostProcessor.class).forEach( extension -> executeAndMaskThrowable(() -> extension.postProcessTestInstance(instance, context))); } @@ -311,31 +302,6 @@ private void invokeMethodInTestExtensionContext(Method method, TestExtensionCont executableInvoker.invoke(method, testInstance, context, registry); } - protected static final class LifecycleAwareDelegatingTestInstanceProvider implements TestInstanceProvider { - - private final TestInstanceProvider testInstanceProvider; - private final Lifecycle lifecycle; - private Object testInstance; - - LifecycleAwareDelegatingTestInstanceProvider(TestInstanceProvider testInstanceProvider, Lifecycle lifecycle) { - this.testInstanceProvider = testInstanceProvider; - this.lifecycle = lifecycle; - } - - @Override - public Object getTestInstance(Optional childExtensionRegistry) { - if (this.lifecycle == Lifecycle.PER_METHOD) { - return this.testInstanceProvider.getTestInstance(childExtensionRegistry); - } - - // else Lifecycle.PER_CLASS - if (this.testInstance == null) { - this.testInstance = this.testInstanceProvider.getTestInstance(childExtensionRegistry); - } - return this.testInstance; - } - } - private static TestInstance.Lifecycle getTestInstanceLifecycle(Class testClass) { // @formatter:off return AnnotationUtils.findAnnotation(testClass, TestInstance.class) diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java index d67a4a708b63..21cef95f2616 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java @@ -19,7 +19,6 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.engine.execution.ExecutableInvoker; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; -import org.junit.jupiter.engine.execution.TestInstanceProvider; import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.commons.meta.API; import org.junit.platform.commons.util.ReflectionUtils; @@ -58,28 +57,14 @@ public final Set getTags() { // --- Node ---------------------------------------------------------------- @Override - protected TestInstanceProvider testInstanceProvider(JupiterEngineExecutionContext parentExecutionContext, + protected Object instantiateTestClass(JupiterEngineExecutionContext parentExecutionContext, ExtensionRegistry registry, ExtensionContext extensionContext) { - - TestInstanceProvider testInstanceProvider = childExtensionRegistry -> { - // Extensions registered for nested classes and below are not to be used for instantiating outer classes - Optional childExtensionRegistryForOuterInstance = Optional.empty(); - - // @formatter:off - Object outerInstance = parentExecutionContext.getTestInstanceProvider().getTestInstance(childExtensionRegistryForOuterInstance); - - ExtensionRegistry registryToUse = childExtensionRegistry.orElse(registry); - Constructor constructor = ReflectionUtils.getDeclaredConstructor(getTestClass()); - Object instance = executableInvoker.invoke(constructor, outerInstance, extensionContext, registryToUse); - - updateTestInstanceInContainerExtensionContext(extensionContext, instance); - invokeTestInstancePostProcessors(instance, registryToUse, extensionContext); - - return instance; - // @formatter:on - }; - - return new LifecycleAwareDelegatingTestInstanceProvider(testInstanceProvider, this.lifecycle); + // Extensions registered for nested classes and below are not to be used for instantiating outer classes + Optional childExtensionRegistryForOuterInstance = Optional.empty(); + Object outerInstance = parentExecutionContext.getTestInstanceProvider().getTestInstance( + childExtensionRegistryForOuterInstance); + Constructor constructor = ReflectionUtils.getDeclaredConstructor(getTestClass()); + return executableInvoker.invoke(constructor, outerInstance, extensionContext, registry); } }