CI/CD Integration: Running Testcontainers in Jenkins and GitHub Actions

Illustration for CI/CD Integration: Running Testcontainers in Jenkins and GitHub Actions
By Last updated:

Continuous Integration and Continuous Deployment (CI/CD) are vital for modern software development. But when your application relies on external services like databases, message brokers, or REST APIs, traditional mocks may not fully capture real-world behavior.
This is where Testcontainers shines: it spins up lightweight, disposable Docker containers during test execution, making integration and end-to-end testing reliable.

In this tutorial, we’ll explore how to seamlessly run Testcontainers-based tests in Jenkins and GitHub Actions, two of the most widely used CI/CD platforms.


Why Run Testcontainers in CI/CD?

  • Reproducibility: No more “works on my machine” issues. Containers guarantee consistent test environments.
  • Isolation: Each test run uses fresh containers, preventing side effects.
  • Cloud-native readiness: Test your microservices against real databases (PostgreSQL, MySQL) or brokers (Kafka, RabbitMQ).
  • Scalability: Automate builds and testing across multiple environments.

Setting Up Testcontainers in Java

Make sure your project has the following dependencies:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>1.19.7</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <version>1.19.7</version>
    <scope>test</scope>
</dependency>

Example JUnit 5 test with Testcontainers:

import org.junit.jupiter.api.Test;
import org.testcontainers.containers.PostgreSQLContainer;
import static org.junit.jupiter.api.Assertions.*;

public class PostgresIntegrationTest {

    @Test
    void testWithPostgres() {
        try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")) {
            postgres.start();
            assertTrue(postgres.isRunning());
            System.out.println("Database URL: " + postgres.getJdbcUrl());
        }
    }
}

Running Testcontainers in Jenkins

Jenkins agents must support Docker since Testcontainers relies on it.

Jenkins Pipeline Configuration

Here’s an example Jenkinsfile:

pipeline {
    agent { label 'docker-enabled' }
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        stage('Build & Test') {
            steps {
                sh './mvnw clean verify -DskipTests=false'
            }
        }
    }
    post {
        always {
            junit '**/target/surefire-reports/*.xml'
        }
    }
}

Key Notes

  • Ensure your Jenkins agent has Docker installed and accessible.
  • For Kubernetes-based Jenkins, mount Docker socket or use DinD (Docker-in-Docker).

Running Testcontainers in GitHub Actions

GitHub Actions provides Docker support out of the box.

GitHub Actions Workflow Example

name: Java CI with Testcontainers

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'
      - name: Build with Maven
        run: ./mvnw clean verify -DskipTests=false

Best Practices

  • Use services: in GitHub Actions if you need external containers (Postgres, MySQL, etc.).
  • Rely on Testcontainers for advanced orchestration instead of manually defining all services.

Case Study: Spring Boot Microservice

A Spring Boot microservice connecting to PostgreSQL and Kafka can be tested in GitHub Actions using Testcontainers.
Instead of relying on external test databases, Testcontainers ensures real infrastructure is spun up consistently across environments.


Best Practices for CI/CD with Testcontainers

  1. Reuse containers for performance using testcontainers.reuse.enable=true.
  2. Run lightweight images (alpine preferred) to save build time.
  3. Fail fast: configure pipelines to stop on first failure.
  4. Log container output for troubleshooting (container.followOutput).
  5. Parallelize builds carefully—allocate sufficient Docker resources.

Version Tracker

  • JUnit 4 → JUnit 5: Native Testcontainers Jupiter integration.
  • Mockito updates: Added static and final method mocking.
  • Testcontainers growth: Support for Docker Compose, LocalStack, and Kubernetes testing.

Conclusion

Integrating Testcontainers with Jenkins and GitHub Actions ensures your CI/CD pipelines are reliable, reproducible, and production-like.
By testing against real infrastructure, teams catch issues earlier, reduce flaky tests, and deliver robust microservices with confidence.


Key Takeaways

  • Testcontainers eliminates “works on my machine” problems.
  • Jenkins requires Docker-enabled agents for Testcontainers.
  • GitHub Actions supports Testcontainers seamlessly via Docker.
  • Best practices: reuse containers, log outputs, optimize for speed.

FAQ

1. What’s the difference between unit and integration tests?
Unit tests isolate logic, while integration tests verify real interactions with dependencies.

2. How do I mock a static method in Mockito?
Use mockStatic() introduced in Mockito 3.4+.

3. How can Testcontainers help in CI/CD pipelines?
It ensures consistent, disposable environments for reliable integration testing.

4. Do I need Docker installed in Jenkins to run Testcontainers?
Yes, Jenkins agents must support Docker.

5. Can GitHub Actions run Testcontainers without extra setup?
Yes, Docker is preinstalled on GitHub-hosted runners.

6. How do I speed up Testcontainers in CI/CD?
Enable container reuse and prefer lightweight images.

7. What if my build agent has no Docker?
Use a DinD (Docker-in-Docker) setup or a dedicated Docker-enabled agent.

8. Can I use Docker Compose with Testcontainers in GitHub Actions?
Yes, Testcontainers supports DockerComposeContainer.

9. How to debug failing Testcontainers builds?
Enable debug logs with -Dorg.testcontainers.

10. Is Testcontainers suitable for production?
No, it’s strictly for development and testing, not production deployments.