Skip to content

Commit fe989bd

Browse files
committed
Pass current ExtensionContext to TestInstancePostProcessors
Prior to this commit, TIPPs were always called with the ClassExtensionContext. However, that only contained a test instance when Lifecycle.PER_CLASS was in use. Now, the ExtensionContext the instance is created for, e.g. the ExtensionContext of a test method with the default lifecycle, is used. Issue: #910
1 parent 50d239f commit fe989bd

17 files changed

+142
-132
lines changed

Diff for: documentation/src/test/java/example/TestInfoDemo.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
class TestInfoDemo {
2525

2626
TestInfoDemo(TestInfo testInfo) {
27-
assertEquals("TestInfo Demo", testInfo.getDisplayName());
27+
String displayName = testInfo.getDisplayName();
28+
assertTrue(displayName.equals("TEST 1") || displayName.equals("test2()"));
2829
}
2930

3031
@BeforeEach

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassExtensionContext.java

+2-12
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import java.lang.reflect.Method;
1717
import java.util.Optional;
1818

19-
import org.junit.jupiter.api.extension.ExtensionContext;
19+
import org.junit.jupiter.engine.execution.AbstractExtensionContext;
2020
import org.junit.jupiter.engine.execution.ThrowableCollector;
2121
import org.junit.platform.commons.meta.API;
2222
import org.junit.platform.engine.EngineExecutionListener;
@@ -28,9 +28,8 @@
2828
public final class ClassExtensionContext extends AbstractExtensionContext<ClassTestDescriptor> {
2929

3030
private final ThrowableCollector throwableCollector;
31-
private Object testInstance;
3231

33-
public ClassExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener,
32+
public ClassExtensionContext(AbstractExtensionContext<?> parent, EngineExecutionListener engineExecutionListener,
3433
ClassTestDescriptor testDescriptor, ThrowableCollector throwableCollector) {
3534

3635
super(parent, engineExecutionListener, testDescriptor);
@@ -47,15 +46,6 @@ public Optional<Class<?>> getTestClass() {
4746
return Optional.of(getTestDescriptor().getTestClass());
4847
}
4948

50-
void setTestInstance(Object testInstance) {
51-
this.testInstance = testInstance;
52-
}
53-
54-
@Override
55-
public Optional<Object> getTestInstance() {
56-
return Optional.ofNullable(this.testInstance);
57-
}
58-
5949
@Override
6050
public Optional<Method> getTestMethod() {
6151
return Optional.empty();

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java

+11-11
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.Collections;
2323
import java.util.List;
2424
import java.util.Set;
25-
import java.util.function.Consumer;
2625
import java.util.function.Function;
2726

2827
import org.junit.jupiter.api.TestInstance;
@@ -32,6 +31,7 @@
3231
import org.junit.jupiter.api.extension.Extension;
3332
import org.junit.jupiter.api.extension.ExtensionContext;
3433
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
34+
import org.junit.jupiter.engine.execution.AbstractExtensionContext;
3535
import org.junit.jupiter.engine.execution.AfterEachMethodAdapter;
3636
import org.junit.jupiter.engine.execution.BeforeEachMethodAdapter;
3737
import org.junit.jupiter.engine.execution.ExecutableInvoker;
@@ -176,29 +176,29 @@ private TestInstanceProvider testInstanceProvider(JupiterEngineExecutionContext
176176
if (this.lifecycle == Lifecycle.PER_CLASS) {
177177
// Eagerly load test instance for BeforeAllCallbacks, if necessary,
178178
// and store the instance in the ExtensionContext.
179-
Object instance = instantiateAndPostProcessTestInstance(parentExecutionContext, extensionContext, registry,
180-
extensionContext::setTestInstance);
181-
return childRegistry -> instance;
179+
Object instance = instantiateAndPostProcessTestInstance(parentExecutionContext, extensionContext, registry);
180+
return (childContext, childRegistry) -> {
181+
childContext.setTestInstance(instance);
182+
return instance;
183+
};
182184
}
183185

184186
// else Lifecycle.PER_METHOD
185-
return childRegistry -> instantiateAndPostProcessTestInstance(parentExecutionContext, extensionContext,
186-
childRegistry.orElse(registry), instance -> {
187-
// no extension context update required
188-
});
187+
return (childContext, childRegistry) -> instantiateAndPostProcessTestInstance(parentExecutionContext,
188+
childContext, childRegistry.orElse(registry));
189189
}
190190

191191
private Object instantiateAndPostProcessTestInstance(JupiterEngineExecutionContext context,
192-
ExtensionContext extensionContext, ExtensionRegistry registry, Consumer<Object> testInstanceConsumer) {
192+
AbstractExtensionContext<?> extensionContext, ExtensionRegistry registry) {
193193

194194
Object instance = instantiateTestClass(context, registry, extensionContext);
195-
testInstanceConsumer.accept(instance);
195+
extensionContext.setTestInstance(instance);
196196
invokeTestInstancePostProcessors(registry, extensionContext);
197197
return instance;
198198
}
199199

200200
protected Object instantiateTestClass(JupiterEngineExecutionContext parentExecutionContext,
201-
ExtensionRegistry registry, ExtensionContext extensionContext) {
201+
ExtensionRegistry registry, AbstractExtensionContext<?> extensionContext) {
202202

203203
Constructor<?> constructor = ReflectionUtils.getDeclaredConstructor(this.testClass);
204204
return executableInvoker.invoke(constructor, extensionContext, registry);

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineDescriptor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import static org.junit.jupiter.engine.extension.ExtensionRegistry.createRegistryWithDefaultExtensions;
1414
import static org.junit.platform.commons.meta.API.Usage.Internal;
1515

16-
import org.junit.jupiter.api.extension.ExtensionContext;
16+
import org.junit.jupiter.engine.execution.AbstractExtensionContext;
1717
import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext;
1818
import org.junit.jupiter.engine.extension.ExtensionRegistry;
1919
import org.junit.platform.commons.meta.API;
@@ -36,7 +36,7 @@ public JupiterEngineDescriptor(UniqueId uniqueId) {
3636
public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) throws Exception {
3737
ExtensionRegistry extensionRegistry = createRegistryWithDefaultExtensions(context.getConfigurationParameters());
3838
EngineExecutionListener executionListener = context.getExecutionListener();
39-
ExtensionContext extensionContext = new JupiterEngineExtensionContext(executionListener, this);
39+
AbstractExtensionContext<?> extensionContext = new JupiterEngineExtensionContext(executionListener, this);
4040

4141
// @formatter:off
4242
return context.extend()

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineExtensionContext.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.lang.reflect.Method;
1717
import java.util.Optional;
1818

19+
import org.junit.jupiter.engine.execution.AbstractExtensionContext;
1920
import org.junit.platform.commons.meta.API;
2021
import org.junit.platform.engine.EngineExecutionListener;
2122

@@ -40,11 +41,6 @@ public Optional<Class<?>> getTestClass() {
4041
return Optional.empty();
4142
}
4243

43-
@Override
44-
public Optional<Object> getTestInstance() {
45-
return Optional.empty();
46-
}
47-
4844
@Override
4945
public Optional<Method> getTestMethod() {
5046
return Optional.empty();

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodExtensionContext.java

+3-11
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import java.lang.reflect.Method;
1717
import java.util.Optional;
1818

19-
import org.junit.jupiter.api.extension.ExtensionContext;
19+
import org.junit.jupiter.engine.execution.AbstractExtensionContext;
2020
import org.junit.jupiter.engine.execution.ThrowableCollector;
2121
import org.junit.platform.commons.meta.API;
2222
import org.junit.platform.engine.EngineExecutionListener;
@@ -27,16 +27,13 @@
2727
@API(Internal)
2828
public final class MethodExtensionContext extends AbstractExtensionContext<MethodTestDescriptor> {
2929

30-
private final Object testInstance;
31-
3230
private final ThrowableCollector throwableCollector;
3331

34-
public MethodExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener,
35-
MethodTestDescriptor testDescriptor, Object testInstance, ThrowableCollector throwableCollector) {
32+
public MethodExtensionContext(AbstractExtensionContext<?> parent, EngineExecutionListener engineExecutionListener,
33+
MethodTestDescriptor testDescriptor, ThrowableCollector throwableCollector) {
3634

3735
super(parent, engineExecutionListener, testDescriptor);
3836

39-
this.testInstance = testInstance;
4037
this.throwableCollector = throwableCollector;
4138
}
4239

@@ -55,11 +52,6 @@ public Optional<Method> getTestMethod() {
5552
return Optional.of(getTestDescriptor().getTestMethod());
5653
}
5754

58-
@Override
59-
public Optional<Object> getTestInstance() {
60-
return Optional.of(this.testInstance);
61-
}
62-
6355
@Override
6456
public Optional<Throwable> getExecutionException() {
6557
return Optional.ofNullable(this.throwableCollector.getThrowable());

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodTestDescriptor.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.junit.jupiter.api.extension.ExtensionContext;
2626
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
2727
import org.junit.jupiter.api.function.Executable;
28+
import org.junit.jupiter.engine.execution.AbstractExtensionContext;
2829
import org.junit.jupiter.engine.execution.AfterEachMethodAdapter;
2930
import org.junit.jupiter.engine.execution.BeforeEachMethodAdapter;
3031
import org.junit.jupiter.engine.execution.ExecutableInvoker;
@@ -78,10 +79,10 @@ public Type getType() {
7879
@Override
7980
public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) throws Exception {
8081
ExtensionRegistry registry = populateNewExtensionRegistry(context);
81-
Object testInstance = context.getTestInstanceProvider().getTestInstance(Optional.of(registry));
8282
ThrowableCollector throwableCollector = new ThrowableCollector();
83-
ExtensionContext extensionContext = new MethodExtensionContext(context.getExtensionContext(),
84-
context.getExecutionListener(), this, testInstance, throwableCollector);
83+
AbstractExtensionContext<?> extensionContext = new MethodExtensionContext(context.getExtensionContext(),
84+
context.getExecutionListener(), this, throwableCollector);
85+
context.getTestInstanceProvider().getTestInstance(extensionContext, Optional.of(registry));
8586

8687
// @formatter:off
8788
return context.extend()

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import java.util.Optional;
1717
import java.util.Set;
1818

19-
import org.junit.jupiter.api.extension.ExtensionContext;
19+
import org.junit.jupiter.engine.execution.AbstractExtensionContext;
2020
import org.junit.jupiter.engine.execution.ExecutableInvoker;
2121
import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext;
2222
import org.junit.jupiter.engine.extension.ExtensionRegistry;
@@ -58,11 +58,11 @@ public final Set<TestTag> getTags() {
5858

5959
@Override
6060
protected Object instantiateTestClass(JupiterEngineExecutionContext parentExecutionContext,
61-
ExtensionRegistry registry, ExtensionContext extensionContext) {
61+
ExtensionRegistry registry, AbstractExtensionContext<?> extensionContext) {
6262

6363
// Extensions registered for nested classes and below are not to be used for instantiating outer classes
6464
Optional<ExtensionRegistry> childExtensionRegistryForOuterInstance = Optional.empty();
65-
Object outerInstance = parentExecutionContext.getTestInstanceProvider().getTestInstance(
65+
Object outerInstance = parentExecutionContext.getTestInstanceProvider().getTestInstance(extensionContext,
6666
childExtensionRegistryForOuterInstance);
6767
Constructor<?> constructor = ReflectionUtils.getDeclaredConstructor(getTestClass());
6868
return executableInvoker.invoke(constructor, outerInstance, extensionContext, registry);

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateExtensionContext.java

+3-11
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import java.lang.reflect.Method;
1717
import java.util.Optional;
1818

19-
import org.junit.jupiter.api.extension.ExtensionContext;
19+
import org.junit.jupiter.engine.execution.AbstractExtensionContext;
2020
import org.junit.platform.commons.meta.API;
2121
import org.junit.platform.engine.EngineExecutionListener;
2222

@@ -26,13 +26,10 @@
2626
@API(Internal)
2727
final class TestTemplateExtensionContext extends AbstractExtensionContext<TestTemplateTestDescriptor> {
2828

29-
private final Object testInstance;
30-
31-
TestTemplateExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener,
32-
TestTemplateTestDescriptor testDescriptor, Object testInstance) {
29+
TestTemplateExtensionContext(AbstractExtensionContext<?> parent, EngineExecutionListener engineExecutionListener,
30+
TestTemplateTestDescriptor testDescriptor) {
3331

3432
super(parent, engineExecutionListener, testDescriptor);
35-
this.testInstance = testInstance;
3633
}
3734

3835
@Override
@@ -45,11 +42,6 @@ public Optional<Class<?>> getTestClass() {
4542
return Optional.of(getTestDescriptor().getTestClass());
4643
}
4744

48-
@Override
49-
public Optional<Object> getTestInstance() {
50-
return Optional.ofNullable(this.testInstance);
51-
}
52-
5345
@Override
5446
public Optional<Method> getTestMethod() {
5547
return Optional.of(getTestDescriptor().getTestMethod());

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
import org.junit.jupiter.api.extension.ExtensionContext;
2121
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
2222
import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;
23+
import org.junit.jupiter.engine.execution.AbstractExtensionContext;
2324
import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext;
2425
import org.junit.jupiter.engine.extension.ExtensionRegistry;
25-
import org.junit.platform.commons.JUnitException;
2626
import org.junit.platform.commons.meta.API;
2727
import org.junit.platform.commons.util.Preconditions;
2828
import org.junit.platform.engine.TestDescriptor;
@@ -59,12 +59,11 @@ public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext conte
5959
ExtensionRegistry registry = populateNewExtensionRegistryFromExtendWith(getTestMethod(),
6060
context.getExtensionRegistry());
6161

62-
// The test instance should be properly maintained by the enclosing class's ExtensionContext.
63-
Object testInstance = context.getExtensionContext().getTestInstance().orElseThrow(() -> new JUnitException(
64-
"Illegal state: test instance not present for method: " + getTestMethod().toGenericString()));
65-
66-
ExtensionContext extensionContext = new TestTemplateExtensionContext(context.getExtensionContext(),
67-
context.getExecutionListener(), this, testInstance);
62+
AbstractExtensionContext<?> extensionContext = new TestTemplateExtensionContext(context.getExtensionContext(),
63+
context.getExecutionListener(), this);
64+
// We don't require a test instance here but provide it to extensions should the enclosing class's
65+
// ExtensionContext already contain one.
66+
extensionContext.setTestInstance(context.getExtensionContext().getTestInstance().orElse(null));
6867

6968
// @formatter:off
7069
return context.extend()

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/AbstractExtensionContext.java renamed to junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/AbstractExtensionContext.java

+20-8
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@
88
* http://www.eclipse.org/legal/epl-v10.html
99
*/
1010

11-
package org.junit.jupiter.engine.descriptor;
11+
package org.junit.jupiter.engine.execution;
1212

1313
import static java.util.stream.Collectors.toCollection;
14+
import static org.junit.platform.commons.meta.API.Usage.Internal;
1415

1516
import java.util.LinkedHashSet;
1617
import java.util.Map;
1718
import java.util.Optional;
1819
import java.util.Set;
1920

2021
import org.junit.jupiter.api.extension.ExtensionContext;
21-
import org.junit.jupiter.engine.execution.ExtensionValuesStore;
22-
import org.junit.jupiter.engine.execution.NamespaceAwareStore;
22+
import org.junit.platform.commons.meta.API;
2323
import org.junit.platform.commons.util.Preconditions;
2424
import org.junit.platform.engine.EngineExecutionListener;
2525
import org.junit.platform.engine.TestDescriptor;
@@ -29,25 +29,28 @@
2929
/**
3030
* @since 5.0
3131
*/
32-
abstract class AbstractExtensionContext<T extends TestDescriptor> implements ExtensionContext {
32+
@API(Internal)
33+
public abstract class AbstractExtensionContext<T extends TestDescriptor> implements ExtensionContext {
3334

3435
private final ExtensionContext parent;
3536
private final EngineExecutionListener engineExecutionListener;
3637
private final T testDescriptor;
3738
private final ExtensionValuesStore valuesStore;
3839

39-
AbstractExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener,
40-
T testDescriptor) {
40+
private Object testInstance;
41+
42+
protected AbstractExtensionContext(AbstractExtensionContext<?> parent,
43+
EngineExecutionListener engineExecutionListener, T testDescriptor) {
4144
this.parent = parent;
4245
this.engineExecutionListener = engineExecutionListener;
4346
this.testDescriptor = testDescriptor;
4447
this.valuesStore = createStore(parent);
4548
}
4649

47-
private ExtensionValuesStore createStore(ExtensionContext parent) {
50+
private ExtensionValuesStore createStore(AbstractExtensionContext<?> parent) {
4851
ExtensionValuesStore parentStore = null;
4952
if (parent != null) {
50-
parentStore = ((AbstractExtensionContext<?>) parent).valuesStore;
53+
parentStore = parent.valuesStore;
5154
}
5255
return new ExtensionValuesStore(parentStore);
5356
}
@@ -62,6 +65,15 @@ public String getDisplayName() {
6265
return getTestDescriptor().getDisplayName();
6366
}
6467

68+
public void setTestInstance(Object testInstance) {
69+
this.testInstance = testInstance;
70+
}
71+
72+
@Override
73+
public Optional<Object> getTestInstance() {
74+
return Optional.ofNullable(this.testInstance);
75+
}
76+
6577
@Override
6678
public void publishReportEntry(Map<String, String> values) {
6779
engineExecutionListener.reportingEntryPublished(this.testDescriptor, ReportEntry.from(values));

Diff for: junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
import static org.junit.platform.commons.meta.API.Usage.Internal;
1414

15-
import org.junit.jupiter.api.extension.ExtensionContext;
1615
import org.junit.jupiter.engine.extension.ExtensionRegistry;
1716
import org.junit.platform.commons.JUnitException;
1817
import org.junit.platform.commons.meta.API;
@@ -56,7 +55,7 @@ public ExtensionRegistry getExtensionRegistry() {
5655
return this.state.extensionRegistry;
5756
}
5857

59-
public ExtensionContext getExtensionContext() {
58+
public AbstractExtensionContext<?> getExtensionContext() {
6059
return this.state.extensionContext;
6160
}
6261

@@ -82,7 +81,7 @@ private static final class State implements Cloneable {
8281
final ConfigurationParameters configurationParameters;
8382
TestInstanceProvider testInstanceProvider;
8483
ExtensionRegistry extensionRegistry;
85-
ExtensionContext extensionContext;
84+
AbstractExtensionContext<?> extensionContext;
8685
ThrowableCollector throwableCollector;
8786

8887
State(EngineExecutionListener executionListener, ConfigurationParameters configurationParameters) {
@@ -121,7 +120,7 @@ public Builder withExtensionRegistry(ExtensionRegistry extensionRegistry) {
121120
return this;
122121
}
123122

124-
public Builder withExtensionContext(ExtensionContext extensionContext) {
123+
public Builder withExtensionContext(AbstractExtensionContext<?> extensionContext) {
125124
newState().extensionContext = extensionContext;
126125
return this;
127126
}

0 commit comments

Comments
 (0)