I have Spring Boot application with a custom ApplicationRunner:

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

@Component
public class Initializer implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        ...
    }
}

I also have a bunch of integration tests:

@Tag("integration")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public abstract class IntegrationTest {
    @Autowired
    private TestRestTemplate client;

    @BeforeAll
    public void beforeAll() {
        ...
    }

    @AfterAll
    public void afterAll() {
        ...
    }
}

public class MyTest extends IntegrationTest {
    @Test
    public void testStuff() {
        ...
    }
}
src/test/resources/junit-platform.properties:
junit.jupiter.testinstance.lifecycle.default = per_class

and everything works fine: when I run the tests the application gets initialized first then the tests run, with the before all running before the test methods.

Now, I'm trying to set up a test listener for my integration tests like this:

@Tag("integration")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestExecutionListeners(IntegrationTest.IntegrationTestTestExecutionListener.class)
public abstract class IntegrationTest {
    @Autowired
    private TestRestTemplate client;

    @BeforeAll
    public void beforeAll() {
        ...
    }

    @AfterAll
    public void afterAll() {
        ...
    }

    public static class IntegrationTestTestExecutionListener implements TestExecutionListener {
        @Override
        public void afterTestExecution(TestContext context) {
            ....
        }
    }
}

When I do so, IntegrationTest's @BeforeAll is now running before my custom ApplicationRunner.

This issue won't happen if I declare the test listener through spring.factories instead of via @TestExecutionListeners. But in that case the listener is enabled for all my tests instead of just the tests inheriting from IntegrationTest.

Comment From: wilkinsona

Declaring your own @TestExecutionListeners as you have done means that the default execution listeners are no longer used. To add to the default behaviour rather than replacing it, you should merge your test execution listeners with the defaults:

@TestExecutionListeners(value = IntegrationTestTestExecutionListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)