Testcontainers: Ambientes de Teste Isolados com Docker

Testes Automatizados · 6 de julho de 2026

📖 4 min de leitura

O Que São Testcontainers?

Testcontainers é uma biblioteca que facilita o uso de containers Docker para testes automatizados. Cada teste consegue seu próprio container isolado.

Benefícios

  • Isolamento – Cada teste tem seu ambiente
    1. Reprodutibilidade – Mesmo ambiente sempre
    2. Realismo – Testa contra serviços reais
    3. Cleanup automático – Containers são removidos

Setup



    org.testcontainers
    testcontainers
    1.19.3



pip install testcontainers


go get github.com/testcontainers/testcontainers-go


npm install @testcontainers


Exemplos

PostgreSQL (Python)

# test_database.py
import pytest
from testcontainers.postgres import PostgresContainer
import psycopg2

@pytest.fixture(scope="module")
def postgres():
with PostgresContainer("postgres:15-alpine") as pg:
yield pg

def test_database_connection(postgres):
# Get connection string
connection_url = postgres.get_connection_url()

# Connect
conn = psycopg2.connect(connection_url)
cursor = conn.cursor()

# Test
cursor.execute("SELECT version();")
version = cursor.fetchone()

assert "PostgreSQL" in version[0]

cursor.close()
conn.close()

def test_create_table(postgres):
conn = psycopg2.connect(postgres.get_connection_url())
cursor = conn.cursor()

cursor.execute("""
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL
)
""")
conn.commit()

# Insert test data
cursor.execute("""
INSERT INTO users (name, email)
VALUES ('João', '[email protected]')
RETURNING id
""")
user_id = cursor.fetchone()[0]

# Verify
cursor.execute("SELECT * FROM users WHERE id = {6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}s", (user_id,))
user = cursor.fetchone()

assert user[1] == "João"

cursor.close()
conn.close()

Redis (Python)

# test_redis.py
import pytest
from testcontainers.redis import RedisContainer
import redis

@pytest.fixture
def redis_container():
with RedisContainer("redis:7-alpine") as redis:
yield redis

def test_redis_basic_operations(redis_container):
client = redis.Redis.from_url(redis_container.get_connection_url())

# Set and get
client.set("key", "value")
assert client.get("key") == b"value"

# Expire
client.setex("temp", 60, "temp_value")
assert client.get("temp") == b"temp_value"

# List
client.lpush("mylist", "a", "b", "c")
assert client.lrange("mylist", 0, -1) == [b'c', b'b', b'a']

client.flushall()

def test_redis_pubsub(redis_container):
client = redis.Redis.from_url(redis_container.get_connection_url())

# Pub/Sub pattern
pubsub = client.pubsub()
pubsub.subscribe("test-channel")

# Give time for subscription
import time
time.sleep(0.5)

# Publish message
client.publish("test-channel", "Hello, World!")

# Receive message
message = pubsub.get_message()
assert message["type"] == "message"
assert message["data"] == b"Hello, World!"

pubsub.close()

MongoDB (Java)

// MongoDBTest.java
import org.testcontainers.containers.MongoDBContainer;
import org.junit.jupiter.api.*;

import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;

import static org.junit.jupiter.api.Assertions.*;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MongoDBTest {

MongoDBContainer mongo = new MongoDBContainer("mongo:7");

@BeforeAll
void startContainer() {
mongo.start();
}

@AfterAll
void stopContainer() {
mongo.stop();
}

@Test
void testMongoConnection() {
String connectionString = mongo.getReplicaSetUrl();

try (var client = MongoClients.create(connectionString)) {
MongoDatabase database = client.getDatabase("testdb");
MongoCollection collection = database.getCollection("users");

// Insert document
org.bson.Document user = new org.bson.Document()
.append("name", "João Silva")
.append("email", "[email protected]");

collection.insertOne(user);

// Find document
org.bson.Document found = collection.find().first();

assertNotNull(found);
assertEquals("João Silva", found.getString("name"));
}
}
}

Docker Compose (Python)

# test_integration.py
import pytest
from testcontainers.compose import DockerCompose

@pytest.fixture(scope="module")
def compose():
with DockerCompose("/path/to/project") as compose:
compose.start()
yield compose
compose.stop()

def test_all_services_running(compose):
# Check if services are healthy
exit_code, output = compose.exec("api", "curl -f http://localhost:8080/health")
assert exit_code == 0

exit_code, output = compose.exec("db", "pg_isready")
assert exit_code == 0

def test_api_with_database(compose):
# API should be able to connect to database
exit_code, output = compose.exec(
"api",
"python -c 'import psycopg2; print("OK")'"
)
assert exit_code == 0
assert "OK" in output.decode()


Multiple Containers

# test_full_stack.py
import pytest
from testcontainers.postgres import PostgresContainer
from testcontainers.redis import RedisContainer
from testcontainers.kafka import KafkaContainer

@pytest.fixture(scope="module")
def test_environment():
# Start all containers
postgres = PostgresContainer("postgres:15")
redis = RedisContainer("redis:7")
kafka = KafkaContainer()

# Start them
pg_url = postgres.start()
redis_url = redis.start()
kafka_bootstrap = kafka.start()

yield {
'postgres': pg_url,
'redis': redis_url,
'kafka': kafka_bootstrap
}

# Cleanup
kafka.stop()
redis.stop()
postgres.stop()


CI Integration

# GitHub Actions
name: Tests with Testcontainers

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
services:
docker:
image: docker:24.0.5-cli
options: --privileged
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Run tests
run: |
docker network create testnet || true
docker compose -f docker-compose.test.yml up -d
docker compose -f docker-compose.test.yml run test


Conclusão

Testcontainers facilita testes com dependências reais. As chaves são:

  1. Isolamento – Cada teste com seu ambiente
  2. Realismo – Testa contra serviços reais
  3. Cleanup – Containers são removidos após testes
  4. CI – Funciona em pipelines
  5. Performance – Mais lento que mocks, mais confiável