Testing that your Spring Boot Application Context is Correctly Configured
Working with Spring/Spring Boot apps, you've very likely landed with the dreaded:
java.lang.IllegalStateException: Failed to load ApplicationContext
It's bad enough when your tests aren't set up, but I've had this after waiting ~2 hours to get a change released to a production environment, only to find we'd missed some config for a specific profile.
Aside: Looking for how to solve this? You may want to read How to fix Failed to load ApplicationContext
in Spring (Boot) applications.
Because of this, the first test I write when I start a new Spring Boot project, or pick up an existing one that doesn't have this test, is:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
// you could use `@ActiveProfiles`, too
class ApplicationIntegrationTest {
@Test
void contextLoads() {
// empty test that would fail if our Spring configuration does not load correctly
}
}
This validates that Spring's context is configured correctly for our application, and makes sure we've got things like bean/property definitions.
However, this test isn't perfect! Although, yes, the test will fail before it executes if the context isn't set, we can get the test passing incorrectly by putting it into the wrong package, or removing the Spring Boot configuration:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.boot.test.context.SpringBootTest;
-@SpringBootTest
class ApplicationIntegrationTest {
@Test
void contextLoads() {
// empty test that would fail if our Spring configuration does not load correctly
}
}
These allow the empty test case to continue to pass, silently, while our application is broken.
Instead, we can improve what we've got to the following test case:
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
@SpringBootTest
class ApplicationIntegrationTest {
@Test
void contextLoads(ApplicationContext context) {
assertThat(context).isNotNull();
}
}
This ensures that we've got the context, and it's been set up successfully. In the cases above where we omit the @SpringBootTest
, this test will fail!
(Using JUnit5, the ApplicationContext
is injected automagically, but we could replace this with an @Autowired
field, too.)
We can also validate that specific beans are instantiated, for instance checking that there's a bean for class IndieAuthController
:
@Test
void hasIndieAuthControllerConfigured(ApplicationContext context) {
assertThat(context.getBean(AccessTokenVerifier.class)).isNotNull();
}
Or for a specific bean's name (i.e via @Qualifier
):
@Test
void hasIndieAuthControllerConfigured(ApplicationContext context) {
assertThat(context.getBean("accessTokenVerifier")).isNotNull();
}