I have a test class with multiple nested test classes inside. The outer test class uses an extension that implements BeforeAllCallback and AfterAllCallback. The methods of these interfaces are called for each nested class when executing the outer test class. Is this expected behaviour? I could not find any documentation specifying this explicitly.
The outer test class has @BeforeAll and @AfterAll methods as well. These are executed once when executing the outer test class. I kind of expected extensions to behave the same.
If this behaviour is indeed expected, is there a way to suppress it?
Here is a minimal code example. Non-custom extensions e.g. SpringExtension show the same behaviour however:
@ExtendWith(MyExtension.class)
public class SomeTest {
@BeforeAll
static void create() {
System.out.println("Call beforeAll of test class");
}
@AfterAll
static void destroy() {
System.out.println("Call afterAll of test class");
}
@Nested
class InnerTest1 {
@Test
void testingA() {
System.out.println("Test 1A");
}
@Test
void testingB() {
System.out.println("Test 1B");
}
}
@Nested
class InnerTest2 {
@Test
void testingA() {
System.out.println("Test 2A");
}
@Test
void testingB() {
System.out.println("Test 2B");
}
}
}
public class MyExtension implements BeforeAllCallback, AfterAllCallback {
public MysqlMockExtension() {
}
@Override
public void beforeAll(final ExtensionContext extensionContext) throws Exception {
System.out.println("Call beforeAll of extension");
}
@Override
public void afterAll(final ExtensionContext extensionContext) throws Exception {
System.out.println("Call afterAll of extension");
}
}
Leads to output:
Call beforeAll of extension
Call beforeAll of test class
Call beforeAll of extension
Test 2A
Test 2B
Call afteeAll of extension
Call beforeAll of extension
Test 1A
Test 1B
Call afteeAll of extension
Call afterAll of test class
Call afteeAll of extension
In JUnit 5, the test lifecycle is driven by four primary annotations i.e. @BeforeAll, @BeforeEach, @AfterEach and @AfterAll. Along with it, each test method must be marked with @Test annotation from package org. junit.
JUnit 4 annotations @Rule and @ClassRule do not exist in JUnit 5. Basically there is a new extension model that can be used to implement extensions with the same functionality. These extensions can be used with the @ExtendWith annotation.
The reason for the observed behaviour is the fact that all extensions you add to a test class in Jupiter is inherited by all its children, be it test methods, or nested test classes. What you could do is check if the class the extension is used on is a top-level class:
class MyExtension implements BeforeAllCallback {
@Override
public void beforeAll(final ExtensionContext extensionContext) throws Exception {
if (extensionContext.getTestClass().isPresent()) {
Class<?> currentClass = extensionContext.getTestClass().get();
if (isNestedClass(currentClass)) {
return;
}
}
System.out.println("Call beforeAll of extension");
}
private boolean isNestedClass(Class<?> currentClass) {
return !ModifierSupport.isStatic(currentClass) && currentClass.isMemberClass();
}
}
As far as I know Jupiter has no mechanism to restrict an extension to the location of the @ExtendWith
annotation. You might open an issue to request this feature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With