<p><strong>Meta Description:</strong> Aprenda Testcontainers: containers Docker para testes, databases, message brokers, como criar ambientes reprodutíveis.</p>

<hr>
<h2>O Que São Testcontainers?</h2>

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

<h3>Benefícios</h3>

<ul><li><strong>Isolamento</strong> - Cada teste tem seu ambiente</li><ol><li><strong>Reprodutibilidade</strong> - Mesmo ambiente sempre</li>
<li><strong>Realismo</strong> - Testa contra serviços reais</li>
<li><strong>Cleanup automático</strong> - Containers são removidos</li></ol></ul>

<hr>
<h2>Setup</h2>

<pre><code><!-- Java/Maven -->

    org.testcontainers
    testcontainers
    1.19.3


<p><!-- Python --><br>pip install testcontainers</p>

<p><!-- Go --><br>go get github.com/testcontainers/testcontainers-go</p>

<p><!-- Node.js --><br>npm install @testcontainers<br></code></pre></p>

<hr>
<h2>Exemplos</h2>

<h3>PostgreSQL (Python)</h3>

<pre><code># test_database.py
import pytest
from testcontainers.postgres import PostgresContainer
import psycopg2

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

<p>def test_database_connection(postgres):<br>    # Get connection string<br>    connection_url = postgres.get_connection_url()</p>

<p># Connect<br>    conn = psycopg2.connect(connection_url)<br>    cursor = conn.cursor()</p>

<p># Test<br>    cursor.execute("SELECT version();")<br>    version = cursor.fetchone()</p>

<p>assert "PostgreSQL" in version[0]</p>

<p>cursor.close()<br>    conn.close()</p>

<p>def test_create_table(postgres):<br>    conn = psycopg2.connect(postgres.get_connection_url())<br>    cursor = conn.cursor()</p>

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

<p># Insert test data<br>    cursor.execute("""<br>        INSERT INTO users (name, email) <br>        VALUES ('João', 'joao@example.com')<br>        RETURNING id<br>    """)<br>    user_id = cursor.fetchone()[0]</p>

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

<p>assert user[1] == "João"</p>

<p>cursor.close()<br>    conn.close()<br></code></pre></p>

<h3>Redis (Python)</h3>

<pre><code># test_redis.py
import pytest
from testcontainers.redis import RedisContainer
import redis

<p>@pytest.fixture<br>def redis_container():<br>    with RedisContainer("redis:7-alpine") as redis:<br>        yield redis</p>

<p>def test_redis_basic_operations(redis_container):<br>    client = redis.Redis.from_url(redis_container.get_connection_url())</p>

<p># Set and get<br>    client.set("key", "value")<br>    assert client.get("key") == b"value"</p>

<p># Expire<br>    client.setex("temp", 60, "temp_value")<br>    assert client.get("temp") == b"temp_value"</p>

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

<p>client.flushall()</p>

<p>def test_redis_pubsub(redis_container):<br>    client = redis.Redis.from_url(redis_container.get_connection_url())</p>

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

<p># Give time for subscription<br>    import time<br>    time.sleep(0.5)</p>

<p># Publish message<br>    client.publish("test-channel", "Hello, World!")</p>

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

<p>pubsub.close()<br></code></pre></p>

<h3>MongoDB (Java)</h3>

<pre><code>// MongoDBTest.java
import org.testcontainers.containers.MongoDBContainer;
import org.junit.jupiter.api.*;

<p>import com.mongodb.client.MongoClients;<br>import com.mongodb.client.MongoCollection;<br>import com.mongodb.client.MongoDatabase;</p>

<p>import static org.junit.jupiter.api.Assertions.*;</p>

<p>@TestInstance(TestInstance.Lifecycle.PER_CLASS)<br>public class MongoDBTest {</p>

<p>MongoDBContainer mongo = new MongoDBContainer("mongo:7");</p>

<p>@BeforeAll<br>    void startContainer() {<br>        mongo.start();<br>    }</p>

<p>@AfterAll<br>    void stopContainer() {<br>        mongo.stop();<br>    }</p>

<p>@Test<br>    void testMongoConnection() {<br>        String connectionString = mongo.getReplicaSetUrl();</p>

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

<p>// Insert document<br>            org.bson.Document user = new org.bson.Document()<br>                .append("name", "João Silva")<br>                .append("email", "joao@example.com");</p>

<p>collection.insertOne(user);</p>

<p>// Find document<br>            org.bson.Document found = collection.find().first();</p>

<p>assertNotNull(found);<br>            assertEquals("João Silva", found.getString("name"));<br>        }<br>    }<br>}<br></code></pre></p>

<h3>Docker Compose (Python)</h3>

<pre><code># test_integration.py
import pytest
from testcontainers.compose import DockerCompose

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

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

<p>exit_code, output = compose.exec("db", "pg_isready")<br>    assert exit_code == 0</p>

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

<hr>
<h2>Multiple Containers</h2>

<pre><code># test_full_stack.py
import pytest
from testcontainers.postgres import PostgresContainer
from testcontainers.redis import RedisContainer
from testcontainers.kafka import KafkaContainer

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

<p># Start them<br>    pg_url = postgres.start()<br>    redis_url = redis.start()<br>    kafka_bootstrap = kafka.start()</p>

<p>yield {<br>        'postgres': pg_url,<br>        'redis': redis_url,<br>        'kafka': kafka_bootstrap<br>    }</p>

<p># Cleanup<br>    kafka.stop()<br>    redis.stop()<br>    postgres.stop()<br></code></pre></p>

<hr>
<h2>CI Integration</h2>

<pre><code># GitHub Actions
name: Tests with Testcontainers

<p>on: [push, pull_request]</p>

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

<p>- name: Set up Docker Buildx<br>        uses: docker/setup-buildx-action@v3</p>

<p>- name: Run tests<br>        run: |<br>          docker network create testnet || true<br>          docker compose -f docker-compose.test.yml up -d<br>          docker compose -f docker-compose.test.yml run test<br></code></pre></p>

<hr>
<h2>Conclusão</h2>

<p>Testcontainers facilita testes com dependências reais. As chaves são:<br><ol><li><strong>Isolamento</strong> - Cada teste com seu ambiente</li><br><li><strong>Realismo</strong> - Testa contra serviços reais</li><br><li><strong>Cleanup</strong> - Containers são removidos após testes</li><br><li><strong>CI</strong> - Funciona em pipelines</li><br><li><strong>Performance</strong> - Mais lento que mocks, mais confiável</li></ol></p>