Testing

Testing Padronizado - C-Suite

Visão Geral

Este documento descreve o framework de testes padronizado para o ecossistema C-Suite, incluindo fixtures, helpers e boas práticas.

Módulo de Testing

Localização

O módulo principal está em: common_testing.py (raiz do projeto)

Características

Uso Básico

1. Testes de API

import pytest
from fastapi import FastAPI
from common_testing import test_client, assert_json_response

app = FastAPI()

@app.get("/api/test")
async def test_endpoint():
    return {"status": "ok"}

def test_endpoint_success(test_client):
    response = test_client(app).get("/api/test")
    data = assert_json_response(response, expected_status=200)
    assert data["status"] == "ok"

2. Testes com Banco de Dados

import pytest
from common_testing import test_db_session

def test_create_organization(test_db_session):
    # Cria organização
    org = Organization(name="Test Org")
    test_db_session.add(org)
    test_db_session.commit()

    # Verifica
    result = test_db_session.query(Organization).filter_by(name="Test Org").first()
    assert result is not None
    assert result.name == "Test Org"

3. Testes com Cache

import pytest
from common_testing import mock_cache
from common_cache import get_cache

def test_cache_operations(mock_cache):
    cache = get_cache()
    cache.set("key", "value", ttl=300)

    value = cache.get("key")
    assert value == "value"

4. Assert Helpers

from common_testing import assert_json_response, assert_error_response

def test_success_response(client):
    response = client.get("/api/success")
    data = assert_json_response(response, expected_status=200)
    assert "data" in data

def test_error_response(client):
    response = client.get("/api/not-found")
    assert_error_response(response, expected_status=404, error_code="ERR_5000")

Estrutura de Testes

Organização Recomendada

app/
├── app/
│   └── main.py
└── tests/
    ├── conftest.py          # Configuração pytest
    ├── test_api.py          # Testes de API
    ├── test_models.py       # Testes de modelos
    ├── test_services.py     # Testes de serviços
    └── integration/
        └── test_e2e.py      # Testes E2E

conftest.py Padrão

import pytest
import sys
from pathlib import Path

# Adiciona raiz do projeto ao path
sys.path.insert(0, str(Path(__file__).resolve().parents[3]))

# Importa fixtures comuns
from common_testing import (
    test_db_session,
    test_client,
    mock_cache,
    temp_dir
)

# Fixtures específicas do app
@pytest.fixture
def app():
    from app.main import app
    return app

Tipos de Testes

1. Unit Tests

Testam unidades isoladas de código:

def test_calculate_score():
    from app.services.scoring import calculate_score

    score = calculate_score(intent=0.8, margin=0.15)
    assert score == 0.95

2. Integration Tests

Testam integração entre componentes:

def test_create_policy_integration(test_db_session):
    from app.services.policies import create_policy

    policy = create_policy(
        org_id=1,
        rule_key="min_margin",
        value=0.15,
        db=test_db_session
    )

    assert policy.rule_key == "min_margin"
    assert policy.rule_value == 0.15

3. API Tests

Testam endpoints da API:

def test_list_policies(test_client, app):
    client = test_client(app)
    response = client.get("/api/policies/1")

    data = assert_json_response(response, expected_status=200)
    assert isinstance(data, list)

4. E2E Tests

Testam fluxos completos:

def test_decision_flow_e2e(test_client, app):
    client = test_client(app)

    # 1. Criar política
    response = client.post("/api/policies/1", json={
        "rule_key": "min_margin",
        "rule_value": 0.15
    })
    assert_json_response(response, expected_status=201)

    # 2. Fazer decisão (deve respeitar política)
    response = client.post("/api/decide", json={
        "customer_id": 123,
        "org_id": 1,
        "candidates": [...]
    })
    data = assert_json_response(response, expected_status=200)
    assert data["decision"]["margin"] >= 0.15

Cobertura de Testes

Meta: > 80% de Cobertura

# Instalar pytest-cov
pip install pytest-cov

# Executar testes com cobertura
pytest --cov=app --cov-report=html --cov-report=term

# Ver relatório HTML
open htmlcov/index.html

Cobertura Mínima por Tipo

Mock e Stubs

Mock de Serviços Externos

from unittest.mock import patch, MagicMock

def test_external_service(mock_cache):
    with patch('httpx.get') as mock_get:
        mock_get.return_value.json.return_value = {"status": "ok"}

        # Testa código que usa httpx
        result = call_external_service()
        assert result["status"] == "ok"

Mock de Banco de Dados

def test_with_mock_db():
    with patch('app.db.get_db') as mock_db:
        mock_session = MagicMock()
        mock_db.return_value = mock_session

        # Testa código que usa banco
        result = get_data()
        mock_session.query.assert_called_once()

Testes de Performance

import time

def test_endpoint_performance(test_client, app):
    client = test_client(app)

    start = time.time()
    response = client.get("/api/endpoint")
    elapsed = time.time() - start

    assert response.status_code == 200
    assert elapsed < 0.1  # Deve responder em < 100ms

Testes de Segurança

def test_sql_injection_protection(test_client, app):
    client = test_client(app)

    # Tenta SQL injection
    response = client.get("/api/data?sort=; DROP TABLE users;--")

    # Deve retornar erro de validação, não executar SQL
    assert_error_response(response, expected_status=400)

def test_authentication_required(test_client, app):
    client = test_client(app)

    # Tenta acessar endpoint protegido sem auth
    response = client.get("/api/protected")

    assert_error_response(response, expected_status=401)

CI/CD Integration

GitHub Actions

name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: '3.9'
      - run: pip install -r requirements.txt
      - run: pip install pytest pytest-cov
      - run: pytest --cov=app --cov-report=xml
      - uses: codecov/codecov-action@v2

GitLab CI

test:
  script:
    - pip install -r requirements.txt
    - pip install pytest pytest-cov
    - pytest --cov=app --cov-report=xml
  coverage: '/TOTAL.*\s+(\d+%)$/'

Boas Práticas

  1. Teste primeiro (TDD): Escreva testes antes do código quando possível
  2. Testes isolados: Cada teste deve ser independente
  3. Nomes descritivos: test_create_policy_with_valid_data
  4. Arrange-Act-Assert: Organize testes em 3 partes
  5. Mock externos: Mock serviços externos e APIs
  6. Teste casos de erro: Teste não apenas sucesso, mas também erros
  7. Mantenha testes atualizados: Atualize testes quando código muda

Próximos Passos

  1. ✅ Módulo de testing criado
  2. ⏳ Criar testes para módulos comuns (common_errors, common_auth, etc.)
  3. ⏳ Adicionar testes em todos os apps
  4. ⏳ Configurar CI/CD para executar testes
  5. ⏳ Aumentar cobertura para > 80%
  6. ⏳ Adicionar testes de performance
  7. ⏳ Adicionar testes de segurança

🔊 Text-to-Speech

1.0x
1.0
Pronto para reproduzir