<p><strong>Meta Description:</strong> Aprenda a usar Docker para QA: imagens otimizadas, docker-compose, multi-stage builds, e como containerizar sua suite de testes.</p>

<hr>
<h2>Por Que Docker para QA?</h2>

<ul><li><strong>Ambientes consistentes</strong> - Same in dev, CI, prod</li><ol><li><strong>Isolamento</strong> - Testes não afetam sistema host</li>
<li><strong>Reproducibilidade</strong> - Resultados consistentes</li>
<li><strong>Escalabilidade</strong> - Múltiplos containers de teste</li>
<li><strong>CI/CD integration</strong> - Fáceis de automatizar</li></ol></ul>

<hr>
<h2>Dockerfile para Testes</h2>

<h3>Multi-Stage Build</h3>

<pre><code># syntax=docker/dockerfile:1

<p># Stage 1: Build<br>FROM node:18-alpine AS builder<br>WORKDIR /app</p>

<p>COPY package*.json ./<br>RUN npm ci --only=production</p>

<p>COPY . .<br>RUN npm run build</p>

<p># Stage 2: Test<br>FROM node:18-alpine AS test<br>WORKDIR /app</p>

<p># Copy dependencies only (layer caching)<br>COPY package*.json ./<br>RUN npm ci</p>

<p># Copy source<br>COPY . .</p>

<p># Install test dependencies<br>RUN npm ci --prefix .</p>

<p># Copy built artifacts<br>COPY --from=builder /app/dist ./dist<br>COPY --from=builder /app/node_modules ./node_modules</p>

<p># Run tests<br>CMD ["npm", "test"]</p>

<p># Stage 3: Production<br>FROM node:18-alpine AS production<br>WORKDIR /app</p>

<p>COPY --from=builder /app/dist ./dist<br>COPY --from=builder /app/node_modules ./node_modules<br>COPY --from=builder /app/package*.json ./</p>

<p>USER node<br>EXPOSE 8080</p>

<p>CMD ["node", "dist/index.js"]<br></code></pre></p>

<h3>Python Tests</h3>

<pre><code>FROM python:3.11-slim

<p>WORKDIR /app</p>

<p># Install system dependencies<br>RUN apt-get update &amp;&amp; apt-get install -y --no-install-recommends <br>    build-essential <br>    libpq-dev <br>    &amp;&amp; rm -rf /var/lib/apt/lists/*</p>

<p># Copy requirements first (layer caching)<br>COPY requirements.txt .<br>RUN pip install --no-cache-dir -r requirements.txt</p>

<p># Copy application<br>COPY . .</p>

<p># Run tests with coverage<br>CMD ["pytest", "-v", "--cov=src", "--cov-report=xml", "--cov-report=html"]<br></code></pre></p>

<hr>
<h2>Docker Compose para Ambientes</h2>

<h3>Desenvolvimento Local</h3>

<pre><code># docker-compose.yml
version: '3.8'

<p>services:<br>  app:<br>    build:<br>      context: .<br>      dockerfile: Dockerfile<br>    ports:<br>      - "3000:3000"<br>    environment:<br>      - NODE_ENV=development<br>      - DATABASE_URL=postgres://test:test@db:5432/test<br>      - REDIS_URL=redis://cache:6379<br>    depends_on:<br>      db:<br>        condition: service_healthy<br>      cache:<br>        condition: service_started<br>    volumes:<br>      - .:/app<br>      - /app/node_modules<br>    command: npm run dev</p>

<p>db:<br>    image: postgres:15-alpine<br>    environment:<br>      POSTGRES_DB: test<br>      POSTGRES_USER: test<br>      POSTGRES_PASSWORD: test<br>    ports:<br>      - "5432:5432"<br>    volumes:<br>      - postgres_data:/var/lib/postgresql/data<br>      - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql<br>    healthcheck:<br>      test: ["CMD-SHELL", "pg_isready -U test -d test"]<br>      interval: 5s<br>      timeout: 5s<br>      retries: 5</p>

<p>cache:<br>    image: redis:7-alpine<br>    ports:<br>      - "6379:6379"<br>    volumes:<br>      - redis_data:/data</p>

<p>test:<br>    build:<br>      context: .<br>      dockerfile: Dockerfile.test<br>    environment:<br>      - DATABASE_URL=postgres://test:test@db:5432/test<br>      - REDIS_URL=redis://cache:6379<br>    depends_on:<br>      db:<br>        condition: service_healthy<br>      cache:<br>        condition: service_started<br>    volumes:<br>      - ./test-results:/app/test-results<br>    command: pytest -v --junitxml=/app/test-results/results.xml</p>

<p>volumes:<br>  postgres_data:<br>  redis_data:<br></code></pre></p>

<h3>CI Environment</h3>

<pre><code># docker-compose.ci.yml
version: '3.8'

<p>services:<br>  app:<br>    build:<br>      context: .<br>      target: test<br>    depends_on:<br>      postgres:<br>        condition: service_healthy<br>      redis:<br>        condition: service_started<br>    environment:<br>      DATABASE_URL: postgres://test:test@postgres:5432/test<br>      REDIS_URL: redis://redis:6379<br>    command: pytest -v --cov=src --cov-report=xml --cov-fail-under=80</p>

<p>postgres:<br>    image: postgres:15-alpine<br>    environment:<br>      POSTGRES_DB: test<br>      POSTGRES_USER: test<br>      POSTGRES_PASSWORD: test<br>    healthcheck:<br>      test: ["CMD-SHELL", "pg_isready -U test"]<br>      interval: 5s<br>      timeout: 5s<br>      retries: 5</p>

<p>redis:<br>    image: redis:7-alpine<br></code></pre></p>

<hr>
<h2>Testcontainers</h2>

<pre><code># testcontainers_example.py
import pytest
from testcontainers.postgres import PostgresContainer
from testcontainers.redis import RedisContainer
from testcontainers.compose import DockerCompose
import psycopg2

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

<p>@pytest.fixture(scope="module")<br>def redis():<br>    with RedisContainer("redis:7") as rd:<br>        yield rd</p>

<p>@pytest.fixture<br>def db_connection(postgres):<br>    conn = psycopg2.connect(postgres.get_connection_url())<br>    yield conn<br>    conn.close()</p>

<p>def test_with_containers(postgres, redis):<br>    """Test usando bancos containerizados"""<br>    # Use containers<br>    db_url = postgres.get_connection_url()<br>    redis_url = redis.get_connection_url()</p>

<p># Your test logic here<br>    conn = psycopg2.connect(db_url)<br>    cursor = conn.cursor()<br>    cursor.execute("SELECT version();")<br>    result = cursor.fetchone()<br>    assert "PostgreSQL" in result[0]<br></code></pre></p>

<hr>
<h2>Docker para Selenium Grid</h2>

<pre><code># selenium-grid.yml
version: '3.8'

<p>services:<br>  selenium-hub:<br>    image: selenium/hub:4.15<br>    ports:<br>      - "4442:4442"<br>      - "4443:4443"<br>      - "4444:4444"<br>    environment:<br>      SE_EVENT_BUS_HOST: selenium-hub<br>      SE_EVENT_BUS_PUBLISH_PORT: 4442<br>      SE_EVENT_BUS_SUBSCRIBE_PORT: 4443</p>

<p>chrome:<br>    image: selenium/node-chrome:4.15<br>    depends_on:<br>      - selenium-hub<br>    environment:<br>      SE_EVENT_BUS_HOST: selenium-hub<br>      SE_EVENT_BUS_PUBLISH_PORT: 4442<br>      SE_EVENT_BUS_SUBSCRIBE_PORT: 4443<br>      SE_NODE_MAX_SESSIONS: 5<br>    shm_size: '2gb'</p>

<p>firefox:<br>    image: selenium/node-firefox:4.15<br>    depends_on:<br>      - selenium-hub<br>    environment:<br>      SE_EVENT_BUS_HOST: selenium-hub<br>      SE_EVENT_BUS_PUBLISH_PORT: 4442<br>      SE_EVENT_BUS_SUBSCRIBE_PORT: 4443<br>      SE_NODE_MAX_SESSIONS: 3</p>

<p>edge:<br>    image: selenium/node-edge:4.15<br>    depends_on:<br>      - selenium-hub<br>    environment:<br>      SE_EVENT_BUS_HOST: selenium-hub<br>      SE_EVENT_BUS_PUBLISH_PORT: 4442<br>      SE_EVENT_BUS_SUBSCRIBE_PORT: 4443<br>      SE_NODE_MAX_SESSIONS: 3<br></code></pre></p>

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

<p>Docker é essencial para QA moderno. As chaves são:<br><ol><li><strong>Multi-stage builds</strong> - Imagens otimizadas</li><br><li><strong>Docker Compose</strong> - Ambientes completos</li><br><li><strong>Testcontainers</strong> - DBs containerizados para testes</li><br><li><strong>Layer caching</strong> - Builds mais rápidos</li><br><li><strong>CI integration</strong> - Automação simplificada</li></ol></p>