This sample project shows different ways to set up reliable integration tests with Spring Boot, Flyway, and Testcontainers. All other technologies used (JDBC, PostgreSQL, JUnit 5) are interchangeable: Using, for example, Hibernate, MariaDB, and TestNG is possible with the same techniques.
All approaches guarantee that all test cases are independent (start with a fresh database) and do not hide errors (like database rollbacks). Furthermore, the test classes can be executed concurrently1 to take advantage of multicore processors. What varies, however, is their execution speed and how much custom plumbing is necessary.
- FlywayMigrationStrategyAuthorRepositoryTest.java uses only facilities provided by Spring Boot but is the slowest (100% runtime).
- FlywayMigrationAuthorRepositoryTest.java requires a TestExecutionListener but is significantly faster than the previous approach (~70% runtime).
- DatabaseDumpAuthorRepositoryTest.java uses a dynamically generated SQL dump to initialise the database. This is the fastest approach (~50% runtime) and stays fast even if the number of Flyway migrations grows. However, you need a fair number of custom Gradle tasks to convert the Flyway migrations into a SQL dump at build time.
The performance numbers are indicative. They depend on your hardware and the specifics of your project, for example, the number of Flyway migrations.
Footnotes
-
The project relies on Gradle's parallel test execution because it uses process isolation to run the tests concurrently. This ensures that tests that run simultaneously do not interfere with each other while keeping the number of running PostgreSQL containers at a reasonable number (one PostgreSQL container per worker process). ↩