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:
Frederico Castro
2025-12-29 08:06:08 -03:00
parent e0692ee49c
commit 143ec401f5
19 changed files with 2899 additions and 0 deletions

View File

@@ -0,0 +1,142 @@
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from httpx import Response
from src.infrastructure.elasticsearch.client import ElasticsearchClient
from src.infrastructure.repositories.consultor_repository_impl import ConsultorRepositoryImpl
from src.domain.services.calculador_pontuacao import CalculadorPontuacao
def create_mock_response(json_data, status_code=200):
response = MagicMock(spec=Response)
response.json.return_value = json_data
response.status_code = status_code
response.raise_for_status = MagicMock()
return response
def criar_doc_consultor(id_pessoa, nome, atuacoes):
return {
"id": id_pessoa,
"dadosPessoais": {"nome": nome},
"atuacoes": atuacoes
}
@pytest.fixture
def es_client():
return ElasticsearchClient(
url="http://localhost:9200",
index="atuacapes_test"
)
@pytest.fixture
def repository(es_client):
return ConsultorRepositoryImpl(es_client)
class TestScrollFlowCompleto:
@pytest.mark.asyncio
async def test_processamento_scroll_com_ranking(self, es_client, repository):
docs_batch_1 = [
criar_doc_consultor(1, "COORD AREA", [{
"tipo": "Coordenação de Área de Avaliação",
"inicio": "01/01/2018",
"dadosCoordenacaoArea": {"tipo": "Coordenador de Área"}
}]),
criar_doc_consultor(2, "COORD ADJUNTO", [{
"tipo": "Coordenação de Área de Avaliação",
"inicio": "01/01/2020",
"dadosCoordenacaoArea": {"tipo": "Coordenador Adjunto"}
}]),
]
docs_batch_2 = [
criar_doc_consultor(3, "CONSULTOR ATIVO", [{
"tipo": "Consultor",
"inicio": "01/01/2015",
"dadosConsultoria": {"situacaoConsultoria": "Atividade Contínua"}
}]),
criar_doc_consultor(4, "PESSOA SEM ATUACAO", []),
]
scroll_1 = {
"_scroll_id": "scroll_1",
"hits": {
"total": {"value": 4},
"hits": [{"_source": d} for d in docs_batch_1]
}
}
scroll_2 = {
"_scroll_id": "scroll_2",
"hits": {"hits": [{"_source": d} for d in docs_batch_2]}
}
scroll_empty = {"_scroll_id": "scroll_3", "hits": {"hits": []}}
ranking_results = []
async def processar_batch(docs, progress):
for doc in docs:
consultor = await repository._construir_consultor(doc)
pontuacao = CalculadorPontuacao.calcular_pontuacao_completa(consultor)
ranking_results.append({
"id": consultor.id_pessoa,
"nome": consultor.nome,
"total": pontuacao.total
})
with patch.object(es_client, '_client') as mock_client:
mock_client.is_closed = False
mock_client.post = AsyncMock(side_effect=[
create_mock_response(scroll_1),
create_mock_response(scroll_2),
create_mock_response(scroll_empty)
])
mock_client.delete = AsyncMock(return_value=create_mock_response({}))
result = await es_client.buscar_todos_consultores(processar_batch, batch_size=2)
assert result["total"] == 4
assert result["processados"] == 4
assert len(ranking_results) == 4
class TestProgressoScroll:
@pytest.mark.asyncio
async def test_progress_callback(self, es_client):
progress_history = []
async def callback(docs, progress):
progress_history.append(progress.copy())
scroll_1 = {
"_scroll_id": "s1",
"hits": {"total": {"value": 100}, "hits": [{"_source": {"id": i}} for i in range(50)]}
}
scroll_2 = {
"_scroll_id": "s2",
"hits": {"hits": [{"_source": {"id": i}} for i in range(50, 100)]}
}
scroll_empty = {"_scroll_id": "s3", "hits": {"hits": []}}
with patch.object(es_client, '_client') as mock_client:
mock_client.is_closed = False
mock_client.post = AsyncMock(side_effect=[
create_mock_response(scroll_1),
create_mock_response(scroll_2),
create_mock_response(scroll_empty)
])
mock_client.delete = AsyncMock(return_value=create_mock_response({}))
await es_client.buscar_todos_consultores(callback, batch_size=50)
assert len(progress_history) == 2
assert progress_history[0]["percentual"] == 50
assert progress_history[0]["processados"] == 50
assert progress_history[1]["percentual"] == 100
assert progress_history[1]["processados"] == 100