Modern Java Testing with JUnit 5 and Testcontainers
Realistic Integration Testing with Dockerized Databases
Unit tests are great for checking isolated business logic. But when your application talks to a database, a message broker, or another external service, unit tests alone won’t cut it.
That’s where integration testing comes in.
In this guide, you’ll learn how to use JUnit 5 and Testcontainers to write realistic integration tests—spinning up Docker containers directly from your test code.
Why Use Testcontainers?
Traditional integration testing often requires:
- Pre-installed databases on developer machines
- Complex test environment configurations
- Manual cleanup after tests
Testcontainers solves this by:
- Running services like PostgreSQL, MySQL, Kafka, Redis, etc. in Docker containers, automatically
- Creating isolated, disposable environments for every test run
- Simplifying setup with Java-friendly APIs
🔗 Testcontainers Official Site: https://www.testcontainers.org/
Benefits of JUnit 5 + Testcontainers
| Feature | Without Testcontainers | With Testcontainers |
|---|---|---|
| Environment Setup | Manual DB setup needed | Automatic Docker containers |
| Test Isolation | Shared databases, risk of leaks | Fresh containers per test run |
| Portability | Works only on dev machines | Runs in CI/CD pipelines too |
| Ease of Use | Complex test configs | Simple Java API calls |
Example: Testing with PostgreSQL
Let’s look at how to set up a PostgreSQL integration test with JUnit 5 and Testcontainers.
1️⃣ Add Dependencies
In your pom.xml (Maven):
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.19.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.1</version>
<scope>test</scope>
</dependency>
2️⃣ Write the Test
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.PostgreSQLContainer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class PostgresIntegrationTest {
@Test
void testPostgresWithContainer() throws Exception {
try (PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:16-alpine")) {
postgres.start();
String jdbcUrl = postgres.getJdbcUrl();
String username = postgres.getUsername();
String password = postgres.getPassword();
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
Statement stmt = conn.createStatement();
stmt.execute("CREATE TABLE demo(id SERIAL PRIMARY KEY, name VARCHAR(255))");
stmt.execute("INSERT INTO demo(name) VALUES ('Testcontainers')");
ResultSet rs = stmt.executeQuery("SELECT name FROM demo WHERE id=1");
rs.next();
String result = rs.getString("name");
assertEquals("Testcontainers", result);
}
postgres.stop();
}
}
}
3️⃣ How It Works
- PostgreSQLContainer spins up a lightweight Docker container
- Test uses the real database, not mocks
- Container is started and stopped automatically
- Your test remains self-contained and repeatable
Use Testcontainers for Other Services
Testcontainers supports more than just databases:
| Service | Module |
|---|---|
| MySQL / MariaDB | mysql / mariadb |
| Redis | testcontainers-redis |
| Kafka | testcontainers-kafka |
| MongoDB | mongodb |
| Elasticsearch | elasticsearch |
🔗 Full Module List: https://www.testcontainers.org/modules/
4️⃣ Integrating with Spring Boot
If you’re using Spring Boot, Testcontainers integrates easily with @DynamicPropertySource:
@Container
static PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:16-alpine");
@DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
🔗 Spring Boot & Testcontainers Docs:
https://www.testcontainers.org/modules/databases/jdbc/#spring-integration
5️⃣ Running in CI/CD
Testcontainers can run in GitHub Actions, GitLab CI, Jenkins, or any CI pipeline that supports Docker.
For faster builds, use Ryuk and Docker-in-Docker (DinD) configurations.
🔗 CI Setup Guide: https://www.testcontainers.org/supported_docker_environment/continuous_integration/
6️⃣ Summary: Why Use Testcontainers?
| Feature | Benefit |
|---|---|
| Realistic Testing | Run tests against real services |
| Easy Setup | No manual Docker commands needed |
| Cross-Environment | Works locally and in CI/CD |
| Supports Many Tools | Databases, Kafka, Selenium, etc. |
Useful Resources
- 🔗 Testcontainers Official Docs
- 🔗 JUnit 5 User Guide
- 🔗 Testcontainers Spring Boot Integration
- 🔗 Testcontainers GitHub Repository
- 🔗 Docker Installation Guide
Conclusion
With JUnit 5 and Testcontainers, you can write robust, realistic integration tests without the headaches of managing local services. You’ll gain:
- More confidence in your tests
- Less environment setup
- Better CI/CD pipelines
It’s time to stop mocking your databases and start testing like it’s production.

