- 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
302 lines
9.8 KiB
Python
302 lines
9.8 KiB
Python
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 == ""
|