Skip to content

Commit

Permalink
Remove duplication and simplify control flow by making it more explicit
Browse files Browse the repository at this point in the history
Issue: #419
  • Loading branch information
marcphilipp authored and sbrannen committed Jun 30, 2017
1 parent 76065a2 commit 902d36a
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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<Object> 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}.
*
* <p>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)));
}
Expand Down Expand Up @@ -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<ExtensionRegistry> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -58,28 +57,14 @@ public final Set<TestTag> 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<ExtensionRegistry> 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<ExtensionRegistry> childExtensionRegistryForOuterInstance = Optional.empty();
Object outerInstance = parentExecutionContext.getTestInstanceProvider().getTestInstance(
childExtensionRegistryForOuterInstance);
Constructor<?> constructor = ReflectionUtils.getDeclaredConstructor(getTestClass());
return executableInvoker.invoke(constructor, outerInstance, extensionContext, registry);
}

}

0 comments on commit 902d36a

Please sign in to comment.