Skip to content

Commit

Permalink
Use current context and registry when instantiating ExecutableInvoker
Browse files Browse the repository at this point in the history
Fixes #3905.
  • Loading branch information
marcphilipp authored Jul 31, 2024
1 parent 8e067d3 commit b693945
Show file tree
Hide file tree
Showing 15 changed files with 73 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ repository on GitHub.

* `TestInstancePostProcessor` extensions can now be registered via the `@ExtendWith`
annotation on non-static fields.
* Methods and constructors invoked via `ExecutableInvoker` now use the same extensions as
the context they are invoked from and the same `ExtensionContext` is passed to
registered instances of `ParameterResolver`.

[[release-notes-5.11.0-RC1-junit-jupiter-deprecations-and-breaking-changes]]
==== Deprecations and Breaking Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ abstract class AbstractExtensionContext<T extends TestDescriptor> implements Ext
private final ExecutableInvoker executableInvoker;

AbstractExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener, T testDescriptor,
JupiterConfiguration configuration, ExecutableInvoker executableInvoker) {
this.executableInvoker = executableInvoker;
JupiterConfiguration configuration,
Function<ExtensionContext, ExecutableInvoker> executableInvokerFactory) {
this.executableInvoker = executableInvokerFactory.apply(this);

Preconditions.notNull(testDescriptor, "TestDescriptor must not be null");
Preconditions.notNull(configuration, "JupiterConfiguration must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExecutableInvoker;
import org.junit.jupiter.api.extension.Extension;
import org.junit.jupiter.api.extension.ExtensionConfigurationException;
import org.junit.jupiter.api.extension.ExtensionContext;
Expand Down Expand Up @@ -179,10 +178,9 @@ public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext conte
registerExtensionsFromInstanceFields(registry, this.testClass);

ThrowableCollector throwableCollector = createThrowableCollector();
ExecutableInvoker executableInvoker = new DefaultExecutableInvoker(context);
ClassExtensionContext extensionContext = new ClassExtensionContext(context.getExtensionContext(),
context.getExecutionListener(), this, this.lifecycle, context.getConfiguration(), throwableCollector,
executableInvoker);
it -> new DefaultExecutableInvoker(it, registry));

// @formatter:off
return context.extend()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.function.Function;

import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExecutableInvoker;
Expand All @@ -38,21 +39,23 @@ final class ClassExtensionContext extends AbstractExtensionContext<ClassBasedTes
* Create a new {@code ClassExtensionContext} with {@link Lifecycle#PER_METHOD}.
*
* @see #ClassExtensionContext(ExtensionContext, EngineExecutionListener, ClassBasedTestDescriptor,
* Lifecycle, JupiterConfiguration, ThrowableCollector, ExecutableInvoker)
* Lifecycle, JupiterConfiguration, ThrowableCollector, Function)
*/
ClassExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener,
ClassBasedTestDescriptor testDescriptor, JupiterConfiguration configuration,
ThrowableCollector throwableCollector, ExecutableInvoker executableInvoker) {
ThrowableCollector throwableCollector,
Function<ExtensionContext, ExecutableInvoker> executableInvokerFactory) {

this(parent, engineExecutionListener, testDescriptor, Lifecycle.PER_METHOD, configuration, throwableCollector,
executableInvoker);
executableInvokerFactory);
}

ClassExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener,
ClassBasedTestDescriptor testDescriptor, Lifecycle lifecycle, JupiterConfiguration configuration,
ThrowableCollector throwableCollector, ExecutableInvoker executableInvoker) {
ThrowableCollector throwableCollector,
Function<ExtensionContext, ExecutableInvoker> executableInvokerFactory) {

super(parent, engineExecutionListener, testDescriptor, configuration, executableInvoker);
super(parent, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory);

this.lifecycle = lifecycle;
this.throwableCollector = throwableCollector;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.function.Function;

import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExecutableInvoker;
Expand All @@ -26,8 +27,8 @@ class DynamicExtensionContext extends AbstractExtensionContext<DynamicNodeTestDe

DynamicExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener,
DynamicNodeTestDescriptor testDescriptor, JupiterConfiguration configuration,
ExecutableInvoker executableInvoker) {
super(parent, engineExecutionListener, testDescriptor, configuration, executableInvoker);
Function<ExtensionContext, ExecutableInvoker> executableInvokerFactory) {
super(parent, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public String getLegacyReportingName() {
@Override
public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) {
DynamicExtensionContext extensionContext = new DynamicExtensionContext(context.getExtensionContext(),
context.getExecutionListener(), this, context.getConfiguration(), new DefaultExecutableInvoker(context));
context.getExecutionListener(), this, context.getConfiguration(),
it -> new DefaultExecutableInvoker(it, context.getExtensionRegistry()));
// @formatter:off
return context.extend()
.withExtensionContext(extensionContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import static org.junit.jupiter.engine.descriptor.JupiterTestDescriptor.toExecutionMode;

import org.apiguardian.api.API;
import org.junit.jupiter.api.extension.ExecutableInvoker;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.engine.config.JupiterConfiguration;
import org.junit.jupiter.engine.execution.DefaultExecutableInvoker;
Expand Down Expand Up @@ -53,9 +52,8 @@ public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext conte
MutableExtensionRegistry extensionRegistry = MutableExtensionRegistry.createRegistryWithDefaultExtensions(
context.getConfiguration());
EngineExecutionListener executionListener = context.getExecutionListener();
ExecutableInvoker executableInvoker = new DefaultExecutableInvoker(context);
ExtensionContext extensionContext = new JupiterEngineExtensionContext(executionListener, this,
context.getConfiguration(), executableInvoker);
context.getConfiguration(), it -> new DefaultExecutableInvoker(it, extensionRegistry));

// @formatter:off
return context.extend()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.function.Function;

import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExecutableInvoker;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestInstances;
import org.junit.jupiter.engine.config.JupiterConfiguration;
import org.junit.platform.engine.EngineExecutionListener;
Expand All @@ -28,9 +30,9 @@ final class JupiterEngineExtensionContext extends AbstractExtensionContext<Jupit

JupiterEngineExtensionContext(EngineExecutionListener engineExecutionListener,
JupiterEngineDescriptor testDescriptor, JupiterConfiguration configuration,
ExecutableInvoker executableInvoker) {
Function<ExtensionContext, ExecutableInvoker> executableInvokerFactory) {

super(null, engineExecutionListener, testDescriptor, configuration, executableInvoker);
super(null, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.function.Function;

import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExecutableInvoker;
Expand All @@ -34,9 +35,10 @@ final class MethodExtensionContext extends AbstractExtensionContext<TestMethodTe

MethodExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener,
TestMethodTestDescriptor testDescriptor, JupiterConfiguration configuration,
ThrowableCollector throwableCollector, ExecutableInvoker executableInvoker) {
ThrowableCollector throwableCollector,
Function<ExtensionContext, ExecutableInvoker> executableInvokerFactory) {

super(parent, engineExecutionListener, testDescriptor, configuration, executableInvoker);
super(parent, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory);

this.throwableCollector = throwableCollector;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExecutableInvoker;
import org.junit.jupiter.api.extension.Extension;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.InvocationInterceptor;
Expand Down Expand Up @@ -99,9 +98,9 @@ public Type getType() {
public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) {
MutableExtensionRegistry registry = populateNewExtensionRegistry(context);
ThrowableCollector throwableCollector = createThrowableCollector();
ExecutableInvoker executableInvoker = new DefaultExecutableInvoker(context);
MethodExtensionContext extensionContext = new MethodExtensionContext(context.getExtensionContext(),
context.getExecutionListener(), this, context.getConfiguration(), throwableCollector, executableInvoker);
context.getExecutionListener(), this, context.getConfiguration(), throwableCollector,
it -> new DefaultExecutableInvoker(it, registry));
throwableCollector.execute(() -> {
TestInstances testInstances = context.getTestInstancesProvider().getTestInstances(registry,
throwableCollector);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.function.Function;

import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExecutableInvoker;
Expand All @@ -31,9 +32,9 @@ final class TestTemplateExtensionContext extends AbstractExtensionContext<TestTe

TestTemplateExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener,
TestTemplateTestDescriptor testDescriptor, JupiterConfiguration configuration, TestInstances testInstances,
ExecutableInvoker executableInvoker) {
Function<ExtensionContext, ExecutableInvoker> executableInvokerFactory) {

super(parent, engineExecutionListener, testDescriptor, configuration, executableInvoker);
super(parent, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory);
this.testInstances = testInstances;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.concurrent.atomic.AtomicInteger;

import org.apiguardian.api.API;
import org.junit.jupiter.api.extension.ExecutableInvoker;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestInstances;
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
Expand Down Expand Up @@ -81,9 +80,9 @@ public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext conte
// The test instance should be properly maintained by the enclosing class's ExtensionContext.
TestInstances testInstances = context.getExtensionContext().getTestInstances().orElse(null);

ExecutableInvoker executableInvoker = new DefaultExecutableInvoker(context);
ExtensionContext extensionContext = new TestTemplateExtensionContext(context.getExtensionContext(),
context.getExecutionListener(), this, context.getConfiguration(), testInstances, executableInvoker);
context.getExecutionListener(), this, context.getConfiguration(), testInstances,
it -> new DefaultExecutableInvoker(it, registry));

// @formatter:off
return context.extend()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ public DefaultExecutableInvoker(ExtensionContext extensionContext, ExtensionRegi
this.extensionRegistry = extensionRegistry;
}

public DefaultExecutableInvoker(JupiterEngineExecutionContext context) {
this(context.getExtensionContext(), context.getExtensionRegistry());
}

@Override
public <T> T invoke(Constructor<T> constructor, Object outerInstance) {
Object[] arguments = resolveParameters(constructor, Optional.empty(), Optional.ofNullable(outerInstance),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ static class ExecuteTestsTwiceTestCase {
static int testInvocations = 0;

@Test
void testWithResolvedParameter(TestInfo testInfo) {
void testWithResolvedParameter(TestInfo testInfo,
@ExtendWith(ExtensionContextParameterResolver.class) ExtensionContext extensionContext) {
assertNotNull(testInfo);
assertEquals(testInfo.getTestMethod().orElseThrow(), extensionContext.getRequiredTestMethod());
testInvocations++;
}

Expand All @@ -57,14 +59,15 @@ static class ExecuteConstructorTwiceTestCase {

static int constructorInvocations = 0;

public ExecuteConstructorTwiceTestCase(TestInfo testInfo) {
public ExecuteConstructorTwiceTestCase(TestInfo testInfo,
@ExtendWith(ExtensionContextParameterResolver.class) ExtensionContext extensionContext) {
assertNotNull(testInfo);
assertEquals(testInfo.getTestClass().orElseThrow(), extensionContext.getRequiredTestClass());
constructorInvocations++;
}

@Test
void test() {

}

}
Expand All @@ -84,9 +87,24 @@ static class ExecuteConstructorTwiceExtension implements BeforeAllCallback {
@Override
public void beforeAll(ExtensionContext context) throws Exception {
context.getExecutableInvoker() //
.invoke(context.getRequiredTestClass().getConstructor(TestInfo.class));
.invoke(context.getRequiredTestClass().getConstructor(TestInfo.class, ExtensionContext.class));
}

}

static class ExtensionContextParameterResolver implements ParameterResolver {

@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return ExtensionContext.class.equals(parameterContext.getParameter().getType());
}

@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return extensionContext;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ void fromJupiterEngineDescriptor() {
UniqueId.root("engine", "junit-jupiter"), configuration);

JupiterEngineExtensionContext engineContext = new JupiterEngineExtensionContext(null, engineTestDescriptor,
configuration, null);
configuration, __ -> null);

// @formatter:off
assertAll("engineContext",
Expand All @@ -100,7 +100,7 @@ void fromClassTestDescriptor() {
ClassTestDescriptor outerClassDescriptor = outerClassDescriptor(nestedClassDescriptor);

ClassExtensionContext outerExtensionContext = new ClassExtensionContext(null, null, outerClassDescriptor,
configuration, null, null);
configuration, null, __ -> null);

// @formatter:off
assertAll("outerContext",
Expand All @@ -118,7 +118,7 @@ void fromClassTestDescriptor() {
// @formatter:on

ClassExtensionContext nestedExtensionContext = new ClassExtensionContext(outerExtensionContext, null,
nestedClassDescriptor, configuration, null, null);
nestedClassDescriptor, configuration, null, __ -> null);
assertThat(nestedExtensionContext.getParent()).containsSame(outerExtensionContext);
}

Expand All @@ -131,18 +131,18 @@ void tagsCanBeRetrievedInExtensionContext() {
outerClassDescriptor.addChild(methodTestDescriptor);

ClassExtensionContext outerExtensionContext = new ClassExtensionContext(null, null, outerClassDescriptor,
configuration, null, null);
configuration, null, __ -> null);

assertThat(outerExtensionContext.getTags()).containsExactly("outer-tag");
assertThat(outerExtensionContext.getRoot()).isSameAs(outerExtensionContext);

ClassExtensionContext nestedExtensionContext = new ClassExtensionContext(outerExtensionContext, null,
nestedClassDescriptor, configuration, null, null);
nestedClassDescriptor, configuration, null, __ -> null);
assertThat(nestedExtensionContext.getTags()).containsExactlyInAnyOrder("outer-tag", "nested-tag");
assertThat(nestedExtensionContext.getRoot()).isSameAs(outerExtensionContext);

MethodExtensionContext methodExtensionContext = new MethodExtensionContext(outerExtensionContext, null,
methodTestDescriptor, configuration, new OpenTest4JAwareThrowableCollector(), null);
methodTestDescriptor, configuration, new OpenTest4JAwareThrowableCollector(), __ -> null);
methodExtensionContext.setTestInstances(DefaultTestInstances.of(new OuterClass()));
assertThat(methodExtensionContext.getTags()).containsExactlyInAnyOrder("outer-tag", "method-tag");
assertThat(methodExtensionContext.getRoot()).isSameAs(outerExtensionContext);
Expand All @@ -161,11 +161,11 @@ void fromMethodTestDescriptor() {
Method testMethod = methodTestDescriptor.getTestMethod();

JupiterEngineExtensionContext engineExtensionContext = new JupiterEngineExtensionContext(null, engineDescriptor,
configuration, null);
configuration, __ -> null);
ClassExtensionContext classExtensionContext = new ClassExtensionContext(engineExtensionContext, null,
classTestDescriptor, configuration, null, null);
classTestDescriptor, configuration, null, __ -> null);
MethodExtensionContext methodExtensionContext = new MethodExtensionContext(classExtensionContext, null,
methodTestDescriptor, configuration, new OpenTest4JAwareThrowableCollector(), null);
methodTestDescriptor, configuration, new OpenTest4JAwareThrowableCollector(), __ -> null);
methodExtensionContext.setTestInstances(DefaultTestInstances.of(testInstance));

// @formatter:off
Expand All @@ -191,7 +191,7 @@ void reportEntriesArePublishedToExecutionContext() {
ClassTestDescriptor classTestDescriptor = outerClassDescriptor(null);
EngineExecutionListener engineExecutionListener = Mockito.spy(EngineExecutionListener.class);
ExtensionContext extensionContext = new ClassExtensionContext(null, engineExecutionListener,
classTestDescriptor, configuration, null, null);
classTestDescriptor, configuration, null, __ -> null);

Map<String, String> map1 = Collections.singletonMap("key", "value");
Map<String, String> map2 = Collections.singletonMap("other key", "other value");
Expand Down Expand Up @@ -222,9 +222,9 @@ void usingStore() {
TestMethodTestDescriptor methodTestDescriptor = methodDescriptor();
ClassTestDescriptor classTestDescriptor = outerClassDescriptor(methodTestDescriptor);
ExtensionContext parentContext = new ClassExtensionContext(null, null, classTestDescriptor, configuration, null,
null);
__ -> null);
MethodExtensionContext childContext = new MethodExtensionContext(parentContext, null, methodTestDescriptor,
configuration, new OpenTest4JAwareThrowableCollector(), null);
configuration, new OpenTest4JAwareThrowableCollector(), __ -> null);
childContext.setTestInstances(DefaultTestInstances.of(new OuterClass()));

ExtensionContext.Store childStore = childContext.getStore(Namespace.GLOBAL);
Expand Down Expand Up @@ -274,9 +274,9 @@ Stream<DynamicTest> configurationParameter() throws Exception {
configuration);

return Stream.of( //
(ExtensionContext) new JupiterEngineExtensionContext(null, engineDescriptor, echo, null), //
new ClassExtensionContext(null, null, classTestDescriptor, echo, null, null), //
new MethodExtensionContext(null, null, methodTestDescriptor, echo, null, null) //
(ExtensionContext) new JupiterEngineExtensionContext(null, engineDescriptor, echo, __ -> null), //
new ClassExtensionContext(null, null, classTestDescriptor, echo, null, __ -> null), //
new MethodExtensionContext(null, null, methodTestDescriptor, echo, null, __ -> null) //
).map(context -> dynamicTest(context.getClass().getSimpleName(),
() -> assertEquals(expected, context.getConfigurationParameter(key))));
}
Expand Down

0 comments on commit b693945

Please sign in to comment.