JUnit test for ApplicationReadyEvent in spring boot app

Viewed 1219

I tried to write test for my spring boot application.

My application has business logic, which start after spring app has been initialized.

There is need to test triggeration of method with annotation @EventListener(ApplicationReadyEvent.class)

Below is a simple example that doesn't work. I expect that inscription "Testing..." appears in the console.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
        MySpringBootTest.MyTestConfig.class
})
public class MySpringBootTest {

    @Test
    public void test() {
    }

    @Configuration
    public static class MyTestConfig {

        @EventListener(ApplicationReadyEvent.class)
        public void init() {
            System.out.println("Testing...");
        }
    }
}

how do I make this example work?

1 Answers

Because you are using @ContextConfiguration Spring application Context is partially loaded and you don't have access to every capability of Spring application Context, however There are many ways to achieve something you want to do. One of them is using TextExecutionListener. I will show you how to use that in both Junit 4 and Junit 5 (jupiter):

Junit 5 (jupiter):

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes= MySpringBootTest.MyTestConfig.class)
@TestExecutionListeners(listeners = {MySpringBootTest.MyTestConfig.class})
public class MySpringBootTest {

    @Test
    public void test1() {
        ....
    }

    @Test
    public void test2() {
        ...
    }

    @Configuration
    public static class MyTestConfig extends AbstractTestExecutionListener {

        @Override
        public void beforeTestClass(TestContext testContext) throws Exception {
            System.out.println("Testing...");
            testContext.getApplicationContext(); //Do anything you want here
        }
    }
}

Here is a quote from Java doc for beforeTestClass method of TestExecutionListener:

Pre-processes a test class before execution of all tests within the class. This method should be called immediately before framework-specific before class lifecycle callbacks.

From the testContext that will be passed to this method you will have access to the application context and test class itself, you can do every thing you want with the test class there.

Junit 4:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MySpringBootTest.MyTestConfig.class})
@TestExecutionListeners(listeners = {MySpringBootTest.CustomTestExecutionListener.class,
        SpringBootDependencyInjectionTestExecutionListener.class})
public class MySpringBootTest {

    @Test
    public void test1() {
        ....
    }

    @Test
    public void test2() {
        ...
    }

    @Configuration
    public static class MyTestConfig  {
        
    }
    
    public static class CustomTestExecutionListener extends AbstractTestExecutionListener {
        @Override
        public void beforeTestClass(TestContext testContext) throws Exception {
            System.out.println("Testing...");
            testContext.getApplicationContext(); //Do anything you want here
        }
    }
} 
Related