Core Java

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 testsspinning 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

FeatureWithout TestcontainersWith Testcontainers
Environment SetupManual DB setup neededAutomatic Docker containers
Test IsolationShared databases, risk of leaksFresh containers per test run
PortabilityWorks only on dev machinesRuns in CI/CD pipelines too
Ease of UseComplex test configsSimple 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:

ServiceModule
MySQL / MariaDBmysql / mariadb
Redistestcontainers-redis
Kafkatestcontainers-kafka
MongoDBmongodb
Elasticsearchelasticsearch

🔗 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?

FeatureBenefit
Realistic TestingRun tests against real services
Easy SetupNo manual Docker commands needed
Cross-EnvironmentWorks locally and in CI/CD
Supports Many ToolsDatabases, Kafka, Selenium, etc.

Useful Resources

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.

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button