diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/JaxbTestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/JaxbTestCase.java index 4e23e989055e7..62110d4baeb4a 100644 --- a/integration-tests/main/src/test/java/io/quarkus/it/main/JaxbTestCase.java +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/JaxbTestCase.java @@ -2,6 +2,10 @@ import static org.hamcrest.Matchers.contains; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -11,12 +15,26 @@ @QuarkusTest public class JaxbTestCase { + private static final AtomicInteger count = new AtomicInteger(0); + + @BeforeEach + public void beforeInEnclosing() { + count.incrementAndGet(); + } + @Nested class SomeClass { + + @BeforeEach + public void beforeInTest() { + count.incrementAndGet(); + } + @Test public void testNews() { RestAssured.when().get("/test/jaxb/getnews").then() .body("author", contains("Emmanuel Bernard")); + Assertions.assertEquals(2, count.get()); } } diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java index 4122ebbad410d..1bae13a1216b3 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java @@ -919,34 +919,19 @@ public void interceptAfterAllMethod(Invocation invocation, ReflectiveInvoc private Object runExtensionMethod(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { resetHangTimeout(); - Method newMethod = null; ClassLoader old = setCCL(runningQuarkusApplication.getClassLoader()); try { - Class c = Class.forName(extensionContext.getRequiredTestClass().getName(), true, + Class testClassFromTCCL = Class.forName(extensionContext.getRequiredTestClass().getName(), true, Thread.currentThread().getContextClassLoader()); - while (c != Object.class) { - if (c.getName().equals(invocationContext.getExecutable().getDeclaringClass().getName())) { - try { - Class[] originalParameterTypes = invocationContext.getExecutable().getParameterTypes(); - List> parameterTypesFromTccl = new ArrayList<>(originalParameterTypes.length); - for (Class type : originalParameterTypes) { - if (type.isPrimitive()) { - parameterTypesFromTccl.add(type); - } else { - parameterTypesFromTccl - .add(Class.forName(type.getName(), true, - Thread.currentThread().getContextClassLoader())); - } - } - newMethod = c.getDeclaredMethod(invocationContext.getExecutable().getName(), - parameterTypesFromTccl.toArray(new Class[0])); - break; - } catch (NoSuchMethodException ignored) { - - } - } - c = c.getSuperclass(); + Method newMethod = determineTCCLExtensionMethod(invocationContext, testClassFromTCCL); + boolean methodFromEnclosing = false; + // this is needed to support before*** and after*** methods that are part of class that encloses the test class + // (the test class is in this case a @Nested test) + if ((newMethod == null) && (testClassFromTCCL.getEnclosingClass() != null)) { + testClassFromTCCL = testClassFromTCCL.getEnclosingClass(); + newMethod = determineTCCLExtensionMethod(invocationContext, testClassFromTCCL); + methodFromEnclosing = true; } if (newMethod == null) { throw new RuntimeException("Could not find method " + invocationContext.getExecutable() + " on test class"); @@ -990,7 +975,13 @@ private Object runExtensionMethod(ReflectiveInvocationContext invocation } } - return newMethod.invoke(actualTestInstance, argumentsFromTccl.toArray(new Object[0])); + Object effectiveTestInstance = actualTestInstance; + if (methodFromEnclosing) { + // TODO: this is a little dodgy, ideally we would need to use the same constructor that was used for the original object + // but it's unlikely(?) we will run into this combo + effectiveTestInstance = testClassFromTCCL.getConstructor().newInstance(); + } + return newMethod.invoke(effectiveTestInstance, argumentsFromTccl.toArray(new Object[0])); } catch (InvocationTargetException e) { throw e.getCause(); } catch (IllegalAccessException | ClassNotFoundException e) { @@ -1000,6 +991,35 @@ private Object runExtensionMethod(ReflectiveInvocationContext invocation } } + private Method determineTCCLExtensionMethod(ReflectiveInvocationContext invocationContext, Class c) + throws ClassNotFoundException { + Method newMethod = null; + while (c != Object.class) { + if (c.getName().equals(invocationContext.getExecutable().getDeclaringClass().getName())) { + try { + Class[] originalParameterTypes = invocationContext.getExecutable().getParameterTypes(); + List> parameterTypesFromTccl = new ArrayList<>(originalParameterTypes.length); + for (Class type : originalParameterTypes) { + if (type.isPrimitive()) { + parameterTypesFromTccl.add(type); + } else { + parameterTypesFromTccl + .add(Class.forName(type.getName(), true, + Thread.currentThread().getContextClassLoader())); + } + } + newMethod = c.getDeclaredMethod(invocationContext.getExecutable().getName(), + parameterTypesFromTccl.toArray(new Class[0])); + break; + } catch (NoSuchMethodException ignored) { + + } + } + c = c.getSuperclass(); + } + return newMethod; + } + @Override public void afterAll(ExtensionContext context) throws Exception { resetHangTimeout();