Spring Boot is great and the best thing about it is how easy it makes it to test your application. So here are some selected tips for writing tests with Spring Boot. The most recent stable Spring Boot version at the time of publishing was 2.5.5.
The configuration and setup of the tests should be as close to them as possible. This reduces the possibility of one test interfering with another and makes it much easier for the reader of the test to grok its purpose. Here are two means to achieve that goal:
@TestConfiguration
As Inner ClassI often use this one to re-configure beans for a single testsuite only. Like so:
@DataJpaTest
class StatementCountTest {
@TestConfiguration
static class ProxyDataSourceConfig {
@Bean
DataSource dataSource(DataSourceProperties baseDataSourceProperties) {
return new StatementListeningDataSource(
baseDataSourceProperties.initializeDataSourceBuilder().build()
);
}
}
@Autowired
private EventRepository eventRepository;
@Test
void executesSingleStatementToFindAllEvents() {
StatementCountValidator validator = new StatementCountValidator();
eventRepository.findAll(); // Uses the `DataSource` implementation provided above internally.
assertThat(validator.getStatementCount()).isEqualTo(1);
}
}
Tests should be as close to your production environment as possible. Declaring your properties with @SpringBootTest(properties = { "x=y", "n=1" })
(same goes for test slices) at the class level helps with that: It allows to
Sounds like innuendo, but it’s supposed to signal something entirely different: Do not use @DirtiesContext
to reset your ApplicationContext because your test suite will become horribly slow.
Rather reset your state (e.g. database) manually through @AfterEach
/@AfterClass
or employ other means which allow Spring to cache your context.
Therefore I’d also suggest to …
Even though it may seem counter-intuitive at first, try using @SpringBootTest
“by default”. My rule of thumb is: for any unit test where you need to nest your mocks and cannot use a test slice. This provides a lot of advantages in my opinion:
@Autowired
is most often much shorter than new ABean(new BBean(MyConfigurationFromSomeWhere()))
.If you’ve never heard of it: Testcontainers provides a truly extraordinary library to run your tests against “real” infrastructure. Your database in your test will be on-par feature-wise with your production database because it’s the same database (only running within a Docker container), your Kafka cluster won’t be some half-assed in-house in-memory implementation, it’ll be the real deal.
I use their Postgres container for my showcase application and it’s just a single line to have an actual Postgres database available for my @SpringBootTest
s:
# In src/test/resources/config/application.properties
spring.datasource.url=jdbc:tc:postgresql:latest:///postgres?TC_DAEMON=true
No configuration needed in the tests themselves! Also note the ?TC_DAEMON=true
. This will keep the container running even without open connections to the database, meaning it’ll be available super quickly for the next test.
Spring Boot is opinionated and so were these tips. I found by honoring them my tests became easier to read, easier to maintain, and more meaningful, sometimes even faster. When in doubt just measure… or find what works for you, a fully-featured application context is waiting at your finger tips.