Pular para conteúdo

RFC-004: Estratégia de Testes e Coverage Targets

Campo Valor
Status Draft
Author Time de Tecnologia
Created 2026-02-05
Updated 2026-02-05
Reunião A ser agendada
Deciders Todo o time técnico

Status

🟡 Draft - RFC em elaboração, aguardando apresentação

Contexto e Problema

Embora tenhamos estratégia de testes documentada em docs/testing/strategy.md, falta formalização de:

  • Coverage targets obrigatórios que bloqueiam PRs
  • Enforcement da pirâmide de testes (60/30/10)
  • Quality gates específicos para CI/CD
  • Standards para Django e FastAPI separadamente
  • Processo de manutenção de testes (flaky tests, testes lentos)

Por que resolver isso agora?

  • Time crescendo, risco de coverage degradar
  • CI/CD precisa de gates claros e automáticos
  • Testes Django (pytest-django) e FastAPI (pytest + moto) têm necessidades diferentes
  • Qualidade dos testes varia entre desenvolvedores
  • Falta clareza sobre quando bloquear PR por testes

Impacto de não resolver

  • Coverage degrada gradualmente ("boiling frog")
  • PRs merged sem testes adequados
  • Bugs em produção que poderiam ser evitados
  • Testes flaky ou lentos não são tratados
  • Inconsistência entre Django e FastAPI testing

Documentação relacionada: - docs/testing/strategy.md - Pirâmide e coverage atual - docs/testing/backend-testing.md - pytest, moto, factories - docs/testing/frontend-testing.md - Jest, RTL - docs/testing/integration-testing.md - SAM Local, Playwright - docs/cicd/github-actions.md - CI/CD workflows

Proposta de Solução

Formalizar estratégia de testes com enforcement automático, adaptada para Django e FastAPI.

Coverage Targets (Obrigatórios)

Backend (Python): - Mínimo global: 70% - Target ideal: 80% - Código crítico (auth, payment, data): 90%+ - PR não pode reduzir coverage global

Frontend (TypeScript/React): - Mínimo global: 60% - Target ideal: 70% - Componentes críticos: 80%+

Exceções (não requerem coverage): - Migrations (Django/Alembic) - Scripts one-off - Arquivos de configuração - Generated code (OpenAPI schemas)

Pirâmide de Testes (Enforcement)

        E2E (10%)
       /         \
      /           \
   Integration (30%)
    /               \
   /                 \
  Unit Tests (60%)

Métricas por PR: - Número de unit tests >= 60% dos testes adicionados - Integration tests entre 20-40% - E2E tests <= 15%

Ferramentas e Setup

Django:

# pytest.ini
[tool:pytest]
DJANGO_SETTINGS_MODULE = app.settings.test
python_files = tests.py test_*.py *_tests.py
addopts = 
    --cov=app
    --cov-report=html
    --cov-report=term-missing
    --cov-fail-under=70
    --strict-markers
    --tb=short
    -p no:warnings

# requirements-test.txt
pytest==8.0.0
pytest-django==4.7.0
pytest-cov==4.1.0
pytest-mock==3.12.0
factory-boy==3.3.0
faker==22.0.0

FastAPI:

# pytest.ini
[tool:pytest]
asyncio_mode = auto
testpaths = tests
addopts =
    --cov=app
    --cov-report=html
    --cov-report=term-missing
    --cov-fail-under=70
    -p no:warnings
    --tb=short

# requirements-test.txt  
pytest==8.0.0
pytest-asyncio==0.23.3
pytest-cov==4.1.0
pytest-mock==3.12.0
moto[all]==5.0.0  # AWS mocking
httpx==0.26.0  # FastAPI test client

Frontend:

// jest.config.js
{
  "collectCoverageFrom": [
    "src/**/*.{ts,tsx}",
    "!src/**/*.d.ts",
    "!src/**/*.stories.tsx",
    "!src/index.tsx"
  ],
  "coverageThresholds": {
    "global": {
      "branches": 60,
      "functions": 60,
      "lines": 60,
      "statements": 60
    }
  },
  "coverageReporters": ["html", "text", "lcov"]
}

Quality Gates (CI/CD)

# .github/workflows/test.yml
name: Tests

on: [push, pull_request]

jobs:
  backend-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run tests
        run: |
          pytest --cov --cov-fail-under=70

      - name: Check coverage diff
        run: |
          # Bloqueia se coverage diminuir
          python scripts/check_coverage_diff.py

      - name: Upload coverage
        uses: codecov/codecov-action@v3

  frontend-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run tests
        run: |
          npm test -- --coverage --coverageThreshold='{"global":{"lines":60}}'

Bloqueios obrigatórios: - ❌ Coverage < 70% (backend) ou < 60% (frontend) - ❌ Coverage diminui em PR - ❌ Testes falhando - ❌ Testes flaky (falha intermitente)

Boas Práticas

Unit Tests:

# Django
def test_user_creation_with_valid_data(db):
    """Test user is created with valid input."""
    # Arrange
    user_data = {
        "email": "test@example.com",
        "password": "SecurePass123!",
        "name": "Test User"
    }

    # Act
    user = User.objects.create_user(**user_data)

    # Assert
    assert user.email == user_data["email"]
    assert user.check_password(user_data["password"])
    assert not user.is_superuser

# FastAPI
@pytest.mark.asyncio
async def test_create_user_endpoint(client):
    """Test POST /api/v1/users creates user."""
    # Arrange
    payload = {
        "email": "test@example.com",
        "name": "Test User"
    }

    # Act
    response = await client.post("/api/v1/users", json=payload)

    # Assert
    assert response.status_code == 201
    assert response.json()["email"] == payload["email"]

Integration Tests:

# Django + Database
def test_user_order_creation_flow(db):
    """Test complete flow: user creates order."""
    user = UserFactory()
    product = ProductFactory(price=100)

    order = create_order(user=user, items=[product])

    assert order.total == 100
    assert order.user == user
    assert order.status == OrderStatus.PENDING

# FastAPI + AWS (mocked)
@mock_sqs
@pytest.mark.asyncio
async def test_publish_user_event():
    """Test event is published to SQS."""
    sqs = boto3.client('sqs', region_name='us-east-1')
    queue = sqs.create_queue(QueueName='events')

    await publish_user_created_event(user_id=123)

    messages = sqs.receive_message(QueueUrl=queue['QueueUrl'])
    assert len(messages['Messages']) == 1

E2E Tests:

// Playwright
test('user can complete checkout flow', async ({ page }) => {
  await page.goto('/products');
  await page.click('[data-testid="add-to-cart"]');
  await page.click('[data-testid="checkout"]');
  await page.fill('[name="card_number"]', '4242424242424242');
  await page.click('[data-testid="submit-payment"]');

  await expect(page).toHaveURL('/order-confirmation');
  await expect(page.locator('.success-message')).toBeVisible();
});

Alternativas Consideradas

Opção 1: Coverage mais agressivo (85%+)

Prós: - Maior garantia de qualidade - Menos bugs

Contras: - Overhead de manutenção de testes - Diminishing returns (últimos 15% são os mais caros) - Pode levar a testes ruins apenas para coverage

Por que não escolhemos: 70-80% é sweet spot entre qualidade e produtividade.

Opção 2: Coverage mais permissivo (50%)

Prós: - Menos overhead - Mais flexibilidade

Contras: - Coverage degrada rapidamente - Muitos bugs passam sem testes

Por que não escolhemos: 50% é muito baixo para produção séria.

Opção 3: Sem enforcement de pirâmide

Prós: - Mais flexibilidade - Devs escolhem tipo de teste

Contras: - Tendência a escrever apenas E2E (lentos e frágeis) - CI lento - Testes flaky

Por que não escolhemos: Pirâmide é best practice comprovada.

Análise de Impacto

Impacto Técnico

  • CI/CD 30-50% mais lento (executar testes)
  • Coverage reports gerados automaticamente
  • PRs podem ser bloqueados por coverage
  • Testes Django e FastAPI separados mas consistentes

Impacto em Negócio

  • ✅ Menos bugs em produção
  • ✅ Refatoração mais segura
  • ✅ Onboarding (testes como documentação)
  • ⚠️ Desenvolvimento inicial ~15% mais lento

Riscos

Risco: Testes ruins só para coverage

Mitigação: Code review de qualidade de testes, não apenas quantidade

Plano de Implementação

Fase 1: Configuração (Semana 1)

  • Configurar pytest.ini, jest.config
  • Adicionar quality gates no CI/CD
  • Documentar standards

Fase 2: Baseline (Semana 2)

  • Medir coverage atual
  • Identificar gaps críticos
  • Criar plano para chegar a 70%

Fase 3: Implementation (Semanas 3-8)

  • Adicionar testes faltantes (priorizar críticos)
  • Refatorar testes ruins
  • Remover testes flaky

Fase 4: Enforcement (Semana 9)

  • Ativar gates que bloqueiam merge
  • Monitorar e ajustar

Métricas de Sucesso

Após 1 mês: - ✅ Coverage backend >= 70% - ✅ Coverage frontend >= 60% - ✅ Zero PRs merged abaixo do threshold

Após 3 meses: - ✅ Coverage backend >= 80% - ✅ Bugs de produção -50% - ✅ Pirâmide 60/30/10 respeitada

Referências