feat(tests): adicionar suite completa de testes automatizados
- 198 testes cobrindo todos os módulos do backend - Testes unitários para calculador de pontuação (56 testes) - Testes para value objects de período (23 testes) - Testes para cliente Elasticsearch com mocks (27 testes) - Testes para repository de consultores (48 testes) - Testes de integração ES + Repository (6 testes) - Testes para API routes FastAPI (23 testes) - Testes para job de processamento (16 testes) - Cobertura de 54% do código
This commit is contained in:
0
backend/tests/interface/__init__.py
Normal file
0
backend/tests/interface/__init__.py
Normal file
0
backend/tests/interface/api/__init__.py
Normal file
0
backend/tests/interface/api/__init__.py
Normal file
301
backend/tests/interface/api/test_routes.py
Normal file
301
backend/tests/interface/api/test_routes.py
Normal file
@@ -0,0 +1,301 @@
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
from fastapi.testclient import TestClient
|
||||
from fastapi import FastAPI
|
||||
|
||||
from src.interface.api.routes import router
|
||||
from src.interface.api.dependencies import (
|
||||
get_repository,
|
||||
get_ranking_store,
|
||||
get_processar_job,
|
||||
get_es_client,
|
||||
get_ranking_oracle_repo,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_repository():
|
||||
repo = AsyncMock()
|
||||
repo.contar_total.return_value = 100
|
||||
return repo
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_ranking_store():
|
||||
store = MagicMock()
|
||||
store.is_ready.return_value = False
|
||||
return store
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_oracle_repo():
|
||||
repo = MagicMock()
|
||||
repo.contar_total.return_value = 1000
|
||||
return repo
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_es_client():
|
||||
return AsyncMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_job():
|
||||
return AsyncMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app(mock_repository, mock_ranking_store, mock_oracle_repo, mock_es_client, mock_job):
|
||||
app = FastAPI()
|
||||
app.include_router(router)
|
||||
|
||||
app.dependency_overrides[get_repository] = lambda: mock_repository
|
||||
app.dependency_overrides[get_ranking_store] = lambda: mock_ranking_store
|
||||
app.dependency_overrides[get_ranking_oracle_repo] = lambda: mock_oracle_repo
|
||||
app.dependency_overrides[get_es_client] = lambda: mock_es_client
|
||||
app.dependency_overrides[get_processar_job] = lambda: mock_job
|
||||
|
||||
return app
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(app):
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
class TestHealthCheck:
|
||||
|
||||
def test_health_check_ok(self, client):
|
||||
response = client.get("/api/v1/health")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["status"] == "ok"
|
||||
|
||||
|
||||
class TestRankingStatus:
|
||||
|
||||
def test_status_inicial(self, client):
|
||||
with patch("src.interface.api.routes.job_status") as mock_status:
|
||||
mock_status.to_dict.return_value = {
|
||||
"running": False,
|
||||
"progress": 0,
|
||||
"processados": 0,
|
||||
"total": 0,
|
||||
"mensagem": "",
|
||||
"batch_atual": 0,
|
||||
"total_batches": 0,
|
||||
"tempo_decorrido": None,
|
||||
"tempo_estimado": None,
|
||||
"inicio": None,
|
||||
"fim": None,
|
||||
"erro": None,
|
||||
}
|
||||
response = client.get("/api/v1/ranking/status")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["running"] is False
|
||||
|
||||
|
||||
class TestRankingPaginado:
|
||||
|
||||
def test_ranking_paginado_sem_oracle(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.contar_total.return_value = 0
|
||||
response = client.get("/api/v1/ranking/paginado")
|
||||
assert response.status_code == 503
|
||||
|
||||
def test_ranking_paginado_com_dados(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.contar_total.return_value = 100
|
||||
mock_oracle_repo.buscar_paginado.return_value = [
|
||||
MagicMock(
|
||||
id_pessoa=1,
|
||||
nome="Consultor 1",
|
||||
posicao=1,
|
||||
pontuacao_total=500,
|
||||
componente_a=200,
|
||||
componente_b=100,
|
||||
componente_c=100,
|
||||
componente_d=50,
|
||||
componente_e=50,
|
||||
ativo=True,
|
||||
anos_atuacao=5.0,
|
||||
json_detalhes="{}"
|
||||
)
|
||||
]
|
||||
response = client.get("/api/v1/ranking/paginado?page=1&size=10")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 100
|
||||
assert len(data["consultores"]) == 1
|
||||
|
||||
def test_ranking_paginado_filtro_ativo(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.contar_total.return_value = 50
|
||||
mock_oracle_repo.buscar_paginado.return_value = []
|
||||
response = client.get("/api/v1/ranking/paginado?ativo=true")
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_ranking_paginado_filtro_selos(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.contar_total.return_value = 0
|
||||
response = client.get("/api/v1/ranking/paginado?selos=COORD_PPG,BPQ")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 0
|
||||
|
||||
|
||||
class TestBuscaPorNome:
|
||||
|
||||
def test_busca_por_nome_encontrado(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.buscar_por_nome.return_value = [
|
||||
{"ID_PESSOA": 1, "NOME": "João Silva", "POSICAO": 10, "PONTUACAO_TOTAL": 500}
|
||||
]
|
||||
response = client.get("/api/v1/ranking/busca?nome=João")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data) == 1
|
||||
assert data[0]["nome"] == "João Silva"
|
||||
|
||||
def test_busca_por_nome_nao_encontrado(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.buscar_por_nome.return_value = []
|
||||
response = client.get("/api/v1/ranking/busca?nome=XYZ")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data) == 0
|
||||
|
||||
def test_busca_por_nome_minimo_3_chars(self, client):
|
||||
response = client.get("/api/v1/ranking/busca?nome=AB")
|
||||
assert response.status_code == 422
|
||||
|
||||
|
||||
class TestRankingEstatisticas:
|
||||
|
||||
def test_estatisticas_sem_dados(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.contar_total.return_value = 0
|
||||
response = client.get("/api/v1/ranking/estatisticas")
|
||||
assert response.status_code == 503
|
||||
|
||||
def test_estatisticas_com_dados(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.contar_total.return_value = 1000
|
||||
mock_oracle_repo.obter_estatisticas.return_value = {
|
||||
"total_consultores": 1000,
|
||||
"total_ativos": 800,
|
||||
"total_inativos": 200,
|
||||
"ultima_atualizacao": "2024-01-01",
|
||||
"pontuacao_media": 150.5,
|
||||
"pontuacao_maxima": 850,
|
||||
"pontuacao_minima": 10,
|
||||
"media_componentes": {"a": 50, "b": 30, "c": 40, "d": 20, "e": 10}
|
||||
}
|
||||
mock_oracle_repo.obter_distribuicao.return_value = [
|
||||
{"faixa": "0-100", "quantidade": 500},
|
||||
{"faixa": "100-200", "quantidade": 300},
|
||||
]
|
||||
response = client.get("/api/v1/ranking/estatisticas")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total_consultores"] == 1000
|
||||
assert data["total_ativos"] == 800
|
||||
|
||||
|
||||
class TestPosicaoRanking:
|
||||
|
||||
def test_posicao_encontrada(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.contar_total.return_value = 1000
|
||||
mock_oracle_repo.buscar_por_id.return_value = MagicMock(
|
||||
id_pessoa=123,
|
||||
nome="João Silva",
|
||||
posicao=42,
|
||||
pontuacao_total=500,
|
||||
componente_a=200,
|
||||
componente_b=100,
|
||||
componente_c=100,
|
||||
componente_d=50,
|
||||
componente_e=50,
|
||||
ativo=True,
|
||||
)
|
||||
response = client.get("/api/v1/ranking/posicao/123")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id_pessoa"] == 123
|
||||
assert data["posicao"] == 42
|
||||
assert data["encontrado"] is True
|
||||
|
||||
def test_posicao_nao_encontrada(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.contar_total.return_value = 1000
|
||||
mock_oracle_repo.buscar_por_id.return_value = None
|
||||
response = client.get("/api/v1/ranking/posicao/99999")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["encontrado"] is False
|
||||
|
||||
|
||||
class TestProcessarRanking:
|
||||
|
||||
def test_processar_ranking_inicia(self, client, mock_job):
|
||||
with patch("src.interface.api.routes.job_status") as mock_status:
|
||||
mock_status.is_running = False
|
||||
response = client.post("/api/v1/ranking/processar")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["sucesso"] is True
|
||||
|
||||
def test_processar_ranking_ja_executando(self, client):
|
||||
with patch("src.interface.api.routes.job_status") as mock_status:
|
||||
mock_status.is_running = True
|
||||
response = client.post("/api/v1/ranking/processar")
|
||||
assert response.status_code == 409
|
||||
|
||||
|
||||
class TestListarSelos:
|
||||
|
||||
def test_listar_selos(self, client):
|
||||
response = client.get("/api/v1/ranking/selos")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "selos" in data
|
||||
assert isinstance(data["selos"], list)
|
||||
|
||||
|
||||
class TestExportarInfo:
|
||||
|
||||
def test_info_exportacao(self, client, mock_oracle_repo):
|
||||
mock_oracle_repo.contar_para_exportacao.return_value = 500
|
||||
response = client.get("/api/v1/ranking/exportar/info")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total_consultores"] == 500
|
||||
assert "estimativa_tamanho_mb" in data
|
||||
|
||||
|
||||
class TestCorrigirEncoding:
|
||||
|
||||
def test_corrigir_encoding_sem_problemas(self):
|
||||
from src.interface.api.routes import corrigir_encoding
|
||||
result = corrigir_encoding("Texto normal")
|
||||
assert result == "Texto normal"
|
||||
|
||||
def test_corrigir_encoding_none(self):
|
||||
from src.interface.api.routes import corrigir_encoding
|
||||
result = corrigir_encoding(None)
|
||||
assert result is None
|
||||
|
||||
def test_corrigir_encoding_vazio(self):
|
||||
from src.interface.api.routes import corrigir_encoding
|
||||
result = corrigir_encoding("")
|
||||
assert result == ""
|
||||
|
||||
|
||||
class TestNormalizarTexto:
|
||||
|
||||
def test_normalizar_texto_acentos(self):
|
||||
from src.interface.api.routes import normalizar_texto
|
||||
result = normalizar_texto("Ciências Ambientais")
|
||||
assert result == "ciencias ambientais"
|
||||
|
||||
def test_normalizar_texto_html_entities(self):
|
||||
from src.interface.api.routes import normalizar_texto
|
||||
result = normalizar_texto("Ciências")
|
||||
assert "ciencias" in result.lower()
|
||||
|
||||
def test_normalizar_texto_vazio(self):
|
||||
from src.interface.api.routes import normalizar_texto
|
||||
result = normalizar_texto("")
|
||||
assert result == ""
|
||||
Reference in New Issue
Block a user