diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleTests.java index 4c6410096657..11d149ace5fb 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleTests.java @@ -10,9 +10,17 @@ package org.junit.jupiter.engine; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; @@ -23,12 +31,22 @@ import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ContainerExtensionContext; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestExtensionContext; +import org.junit.jupiter.api.extension.TestInstancePostProcessor; +import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.engine.test.event.ExecutionEventRecorder; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; /** - * Tests for {@link TestInstance @TestInstance} lifecycle support. + * Integration tests for {@link TestInstance @TestInstance} lifecycle support. * * @since 5.0 */ @@ -37,6 +55,8 @@ class TestInstanceLifecycleTests extends AbstractJupiterTestEngineTests { + private static final Map instanceMap = new HashMap<>(); + private static int instanceCount; private static int nestedInstanceCount; private static int beforeAllCount; @@ -46,6 +66,7 @@ class TestInstanceLifecycleTests extends AbstractJupiterTestEngineTests { @BeforeEach void init() { + instanceMap.clear(); instanceCount = 0; nestedInstanceCount = 0; beforeAllCount = 0; @@ -56,67 +77,195 @@ void init() { @Test void instancePerMethod() { + Class testClass = InstancePerMethodTestCase.class; int containers = 2; int tests = 2; int instances = 2; int nestedInstances = 0; int allMethods = 1; int eachMethods = 2; + String postProcessTestInstanceKey = postProcessTestInstanceKey(testClass); + String beforeAllCallbackKey = beforeAllCallbackKey(testClass); + String afterAllCallbackKey = afterAllCallbackKey(testClass); + String beforeEachCallbackKey = beforeEachCallbackKey(testClass); + String afterEachCallbackKey = afterEachCallbackKey(testClass); + + performAssertions(testClass, containers, tests, instances, nestedInstances, allMethods, eachMethods); + + assertThat(instanceMap.keySet()).containsExactlyInAnyOrder(postProcessTestInstanceKey, beforeAllCallbackKey, + afterAllCallbackKey, beforeEachCallbackKey, afterEachCallbackKey); - performAssertions(InstancePerMethodTestCase.class, containers, tests, instances, nestedInstances, allMethods, - eachMethods); + assertNull(instanceMap.get(beforeAllCallbackKey)); + assertNull(instanceMap.get(afterAllCallbackKey)); + + Object instance = instanceMap.get(beforeEachCallbackKey); + assertNotNull(instance); + assertSame(instance, instanceMap.get(afterEachCallbackKey)); + assertSame(instance, instanceMap.get(postProcessTestInstanceKey)); } @Test void instancePerClass() { + Class testClass = InstancePerClassTestCase.class; int containers = 2; int tests = 2; int instances = 1; int nestedInstances = 0; int allMethods = 2; int eachMethods = 2; - - performAssertions(InstancePerClassTestCase.class, containers, tests, instances, nestedInstances, allMethods, - eachMethods); + String postProcessTestInstanceKey = postProcessTestInstanceKey(testClass); + String beforeAllCallbackKey = beforeAllCallbackKey(testClass); + String afterAllCallbackKey = afterAllCallbackKey(testClass); + String beforeEachCallbackKey = beforeEachCallbackKey(testClass); + String afterEachCallbackKey = afterEachCallbackKey(testClass); + + performAssertions(testClass, containers, tests, instances, nestedInstances, allMethods, eachMethods); + + assertThat(instanceMap.keySet()).containsExactlyInAnyOrder(postProcessTestInstanceKey, beforeAllCallbackKey, + afterAllCallbackKey, beforeEachCallbackKey, afterEachCallbackKey); + + Object instance = instanceMap.get(beforeAllCallbackKey); + assertNotNull(instance); + assertSame(instance, instanceMap.get(afterAllCallbackKey)); + assertSame(instance, instanceMap.get(beforeEachCallbackKey)); + assertSame(instance, instanceMap.get(afterEachCallbackKey)); + assertSame(instance, instanceMap.get(postProcessTestInstanceKey)); } @Test void instancePerMethodWithNestedTestClass() { + Class testClass = InstancePerMethodOuterTestCase.class; + Class nestedTestClass = InstancePerMethodOuterTestCase.NestedInstancePerMethodTestCase.class; int containers = 3; int tests = 3; int instances = 3; int nestedInstances = 2; int allMethods = 1; int eachMethods = 2; - - performAssertions(InstancePerMethodOuterTestCase.class, containers, tests, instances, nestedInstances, - allMethods, eachMethods); + String postProcessTestInstanceKey = postProcessTestInstanceKey(testClass); + String nestedPostProcessTestInstanceKey = postProcessTestInstanceKey(nestedTestClass); + String beforeAllCallbackKey = beforeAllCallbackKey(testClass); + String afterAllCallbackKey = afterAllCallbackKey(testClass); + String beforeEachCallbackKey = beforeEachCallbackKey(testClass); + String afterEachCallbackKey = afterEachCallbackKey(testClass); + String nestedBeforeAllCallbackKey = beforeAllCallbackKey(nestedTestClass); + String nestedAfterAllCallbackKey = afterAllCallbackKey(nestedTestClass); + String nestedBeforeEachCallbackKey = beforeEachCallbackKey(nestedTestClass); + String nestedAfterEachCallbackKey = afterEachCallbackKey(nestedTestClass); + + performAssertions(testClass, containers, tests, instances, nestedInstances, allMethods, eachMethods); + + assertThat(instanceMap.keySet()).containsExactlyInAnyOrder(postProcessTestInstanceKey, + nestedPostProcessTestInstanceKey, beforeAllCallbackKey, afterAllCallbackKey, beforeEachCallbackKey, + afterEachCallbackKey, nestedBeforeAllCallbackKey, nestedAfterAllCallbackKey, nestedBeforeEachCallbackKey, + nestedAfterEachCallbackKey); + + assertNull(instanceMap.get(beforeAllCallbackKey)); + assertNull(instanceMap.get(afterAllCallbackKey)); + assertNull(instanceMap.get(nestedBeforeAllCallbackKey)); + assertNull(instanceMap.get(nestedAfterAllCallbackKey)); + + Object instance = instanceMap.get(beforeEachCallbackKey); + assertNotNull(instance); + assertSame(instance, instanceMap.get(afterEachCallbackKey)); + + Object nestedInstance = instanceMap.get(nestedBeforeEachCallbackKey); + assertNotSame(instance, nestedInstance); + assertSame(nestedInstance, instanceMap.get(nestedAfterEachCallbackKey)); + assertSame(nestedInstance, instanceMap.get(nestedPostProcessTestInstanceKey)); + + Object outerInstance = ReflectionUtils.getOuterInstance(nestedInstance, testClass).get(); + assertSame(outerInstance, instanceMap.get(postProcessTestInstanceKey)); } @Test void instancePerClassWithNestedTestClass() { + Class testClass = InstancePerClassOuterTestCase.class; + Class nestedTestClass = InstancePerClassOuterTestCase.NestedInstancePerClassTestCase.class; int containers = 3; int tests = 3; int instances = 1; int nestedInstances = 1; int allMethods = 2; int eachMethods = 2; - - performAssertions(InstancePerClassOuterTestCase.class, containers, tests, instances, nestedInstances, - allMethods, eachMethods); + String postProcessTestInstanceKey = postProcessTestInstanceKey(testClass); + String nestedPostProcessTestInstanceKey = postProcessTestInstanceKey(nestedTestClass); + String beforeAllCallbackKey = beforeAllCallbackKey(testClass); + String afterAllCallbackKey = afterAllCallbackKey(testClass); + String beforeEachCallbackKey = beforeEachCallbackKey(testClass); + String afterEachCallbackKey = afterEachCallbackKey(testClass); + String nestedBeforeAllCallbackKey = beforeAllCallbackKey(nestedTestClass); + String nestedAfterAllCallbackKey = afterAllCallbackKey(nestedTestClass); + String nestedBeforeEachCallbackKey = beforeEachCallbackKey(nestedTestClass); + String nestedAfterEachCallbackKey = afterEachCallbackKey(nestedTestClass); + + performAssertions(testClass, containers, tests, instances, nestedInstances, allMethods, eachMethods); + + assertThat(instanceMap.keySet()).containsExactlyInAnyOrder(postProcessTestInstanceKey, + nestedPostProcessTestInstanceKey, beforeAllCallbackKey, afterAllCallbackKey, beforeEachCallbackKey, + afterEachCallbackKey, nestedBeforeAllCallbackKey, nestedAfterAllCallbackKey, nestedBeforeEachCallbackKey, + nestedAfterEachCallbackKey); + + Object instance = instanceMap.get(beforeAllCallbackKey); + assertNotNull(instance); + assertSame(instance, instanceMap.get(afterAllCallbackKey)); + assertSame(instance, instanceMap.get(beforeEachCallbackKey)); + assertSame(instance, instanceMap.get(afterEachCallbackKey)); + + Object nestedInstance = instanceMap.get(nestedBeforeAllCallbackKey); + assertNotSame(instance, nestedInstance); + assertSame(nestedInstance, instanceMap.get(nestedAfterAllCallbackKey)); + assertSame(nestedInstance, instanceMap.get(nestedBeforeEachCallbackKey)); + assertSame(nestedInstance, instanceMap.get(nestedAfterEachCallbackKey)); + assertSame(nestedInstance, instanceMap.get(nestedPostProcessTestInstanceKey)); + + Object outerInstance = ReflectionUtils.getOuterInstance(nestedInstance, testClass).get(); + assertSame(outerInstance, instanceMap.get(postProcessTestInstanceKey)); } @Test void instancePerMethodOnOuterTestClassWithInstancePerClassOnNestedTestClass() { + Class testClass = MixedLifecyclesOuterTestCase.class; + Class nestedTestClass = MixedLifecyclesOuterTestCase.NestedInstancePerClassTestCase.class; int containers = 3; int tests = 3; int instances = 2; int nestedInstances = 1; int allMethods = 1; int eachMethods = 5; - - performAssertions(MixedLifecyclesOuterTestCase.class, containers, tests, instances, nestedInstances, allMethods, - eachMethods); + String postProcessTestInstanceKey = postProcessTestInstanceKey(testClass); + String nestedPostProcessTestInstanceKey = postProcessTestInstanceKey(nestedTestClass); + String beforeAllCallbackKey = beforeAllCallbackKey(testClass); + String afterAllCallbackKey = afterAllCallbackKey(testClass); + String beforeEachCallbackKey = beforeEachCallbackKey(testClass); + String afterEachCallbackKey = afterEachCallbackKey(testClass); + String nestedBeforeAllCallbackKey = beforeAllCallbackKey(nestedTestClass); + String nestedAfterAllCallbackKey = afterAllCallbackKey(nestedTestClass); + String nestedBeforeEachCallbackKey = beforeEachCallbackKey(nestedTestClass); + String nestedAfterEachCallbackKey = afterEachCallbackKey(nestedTestClass); + + performAssertions(testClass, containers, tests, instances, nestedInstances, allMethods, eachMethods); + + assertThat(instanceMap.keySet()).containsExactlyInAnyOrder(postProcessTestInstanceKey, + nestedPostProcessTestInstanceKey, beforeAllCallbackKey, afterAllCallbackKey, beforeEachCallbackKey, + afterEachCallbackKey, nestedBeforeAllCallbackKey, nestedAfterAllCallbackKey, nestedBeforeEachCallbackKey, + nestedAfterEachCallbackKey); + + assertNull(instanceMap.get(beforeAllCallbackKey)); + assertNull(instanceMap.get(afterAllCallbackKey)); + + Object instance = instanceMap.get(beforeEachCallbackKey); + assertSame(instance, instanceMap.get(afterEachCallbackKey)); + + Object nestedInstance = instanceMap.get(nestedBeforeAllCallbackKey); + assertNotSame(instance, nestedInstance); + assertSame(nestedInstance, instanceMap.get(nestedAfterAllCallbackKey)); + assertSame(nestedInstance, instanceMap.get(nestedBeforeEachCallbackKey)); + assertSame(nestedInstance, instanceMap.get(nestedAfterEachCallbackKey)); + assertSame(nestedInstance, instanceMap.get(nestedPostProcessTestInstanceKey)); + + Object outerInstance = ReflectionUtils.getOuterInstance(nestedInstance, testClass).get(); + assertSame(outerInstance, instanceMap.get(postProcessTestInstanceKey)); } private void performAssertions(Class testClass, int containers, int tests, int instances, int nestedInstances, @@ -142,8 +291,29 @@ private void performAssertions(Class testClass, int containers, int tests, in // @formatter:on } + private static String beforeAllCallbackKey(Class testClass) { + return testClass.getSimpleName() + ".BeforeAllCallback"; + } + + private static String afterAllCallbackKey(Class testClass) { + return testClass.getSimpleName() + ".AfterAllCallback"; + } + + private static String beforeEachCallbackKey(Class testClass) { + return testClass.getSimpleName() + ".BeforeEachCallback"; + } + + private static String afterEachCallbackKey(Class testClass) { + return testClass.getSimpleName() + ".AfterEachCallback"; + } + + private static String postProcessTestInstanceKey(Class testClass) { + return testClass.getSimpleName() + ".TestInstancePostProcessor"; + } + // ------------------------------------------------------------------------- + @ExtendWith(InstanceTrackingExtension.class) // The following is commented out b/c it's the default. // @TestInstance(Lifecycle.PER_METHOD) private static class InstancePerMethodTestCase { @@ -201,6 +371,7 @@ void afterAll(TestInfo testInfo) { } + @ExtendWith(InstanceTrackingExtension.class) // The following is commented out b/c it's the default. // @TestInstance(Lifecycle.PER_METHOD) private static class InstancePerMethodOuterTestCase { @@ -218,6 +389,7 @@ static void beforeAll(TestInfo testInfo) { @Test void outerTest() { + assertSame(this, instanceMap.get(postProcessTestInstanceKey(getClass()))); } @AfterAll @@ -243,10 +415,12 @@ void beforeEach() { @Test void test1() { + assertSame(this, instanceMap.get(postProcessTestInstanceKey(getClass()))); } @Test void test2() { + assertSame(this, instanceMap.get(postProcessTestInstanceKey(getClass()))); } @AfterEach @@ -256,6 +430,7 @@ void afterEach() { } } + @ExtendWith(InstanceTrackingExtension.class) @TestInstance(Lifecycle.PER_CLASS) private static class InstancePerClassOuterTestCase { @@ -272,6 +447,7 @@ static void beforeAll(TestInfo testInfo) { @Test void outerTest() { + assertSame(this, instanceMap.get(postProcessTestInstanceKey(getClass()))); } @AfterAll @@ -302,10 +478,12 @@ void beforeEach() { @Test void test1() { + assertSame(this, instanceMap.get(postProcessTestInstanceKey(getClass()))); } @Test void test2() { + assertSame(this, instanceMap.get(postProcessTestInstanceKey(getClass()))); } @AfterEach @@ -321,6 +499,7 @@ void afterAll(TestInfo testInfo) { } } + @ExtendWith(InstanceTrackingExtension.class) // The following is commented out b/c it's the default. // @TestInstance(Lifecycle.PER_METHOD) private static class MixedLifecyclesOuterTestCase { @@ -337,6 +516,7 @@ void beforeEach() { @Test void outerTest() { + assertSame(this, instanceMap.get(postProcessTestInstanceKey(getClass()))); } @AfterEach @@ -366,10 +546,12 @@ void beforeEach() { @Test void test1() { + assertSame(this, instanceMap.get(postProcessTestInstanceKey(getClass()))); } @Test void test2() { + assertSame(this, instanceMap.get(postProcessTestInstanceKey(getClass()))); } @AfterEach @@ -385,4 +567,37 @@ void afterAll(TestInfo testInfo) { } } + private static class InstanceTrackingExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, + AfterEachCallback, TestInstancePostProcessor { + + @Override + public void beforeAll(ContainerExtensionContext context) { + instanceMap.put(beforeAllCallbackKey(context.getTestClass().get()), context.getTestInstance().orElse(null)); + } + + @Override + public void afterAll(ContainerExtensionContext context) { + instanceMap.put(afterAllCallbackKey(context.getTestClass().get()), context.getTestInstance().orElse(null)); + } + + @Override + public void afterEach(TestExtensionContext context) throws Exception { + instanceMap.put(beforeEachCallbackKey(context.getTestClass().get()), + context.getTestInstance().orElse(null)); + } + + @Override + public void beforeEach(TestExtensionContext context) throws Exception { + instanceMap.put(afterEachCallbackKey(context.getTestClass().get()), context.getTestInstance().orElse(null)); + } + + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { + assertNotNull(testInstance); + assertFalse(context.getTestInstance().isPresent()); + instanceMap.put(postProcessTestInstanceKey(context.getTestClass().get()), testInstance); + } + + } + }