Este documento descreve como executar e contribuir com testes no projeto Agent Portfolio Optimizer.
tests/
├── conftest.py # Configurações e fixtures compartilhadas
├── test_coleta_dados/ # Testes para módulos de coleta de dados
├── test_integration/ # Testes de integração
├── test_state_outputs/ # Testes para estados e outputs
├── test_tratando_dados/ # Testes para tratamento de dados
└── test_utils/ # Testes para utilitários
-
Usando o script Python (Recomendado):
python scripts/run_tests.py --all
-
Usando Make:
make test_all
-
Usando pytest diretamente:
uv run pytest
# Todos os testes com cobertura e linting
python scripts/run_tests.py --all
# Apenas testes unitários
python scripts/run_tests.py --unit
# Apenas testes de integração
python scripts/run_tests.py --integration
# Testes rápidos (exclui testes marcados como 'slow')
python scripts/run_tests.py --fast
# Testes com relatório de cobertura
python scripts/run_tests.py --coverage
# Apenas linting
python scripts/run_tests.py --lint
# Apenas verificação de tipos
python scripts/run_tests.py --type-checkmake test # Executa testes básicos
make test_coverage # Testes com cobertura
make test_unit # Apenas testes unitários
make test_integration # Apenas testes de integração
make test_fast # Testes rápidos
make test_all # Todos os checksUse marcadores para categorizar seus testes:
import pytest
@pytest.mark.unit
def test_funcao_simples():
"""Teste unitário básico."""
pass
@pytest.mark.integration
def test_workflow_completo():
"""Teste de integração."""
pass
@pytest.mark.slow
def test_operacao_demorada():
"""Teste que demora para executar."""
pass
@pytest.mark.external_api
def test_chamada_api_externa():
"""Teste que faz chamadas para APIs externas."""
passdef test_exemplo(mock_ticker_data, mock_historical_data):
"""Exemplo usando fixtures de dados mock."""
assert mock_ticker_data['symbol'] == 'PETR4.SA'
assert len(mock_historical_data) == 100def test_exemplo_com_mock_yfinance(mock_yfinance):
"""Exemplo usando mock do yfinance."""
mock_yfinance.info = {'symbol': 'PETR4.SA'}
# Seu teste aqui"""Testes para o módulo ExemploModulo."""
import pytest
from unittest.mock import Mock, patch
from portfolio_optimizer.modulo import ExemploClasse
class TestExemploClasse:
"""Testes para a classe ExemploClasse."""
def test_metodo_sucesso(self):
"""Testa execução bem-sucedida do método."""
# Arrange
instancia = ExemploClasse("parametro")
# Act
resultado = instancia.metodo()
# Assert
assert resultado == "esperado"
@patch('portfolio_optimizer.modulo.dependencia_externa')
def test_metodo_com_mock(self, mock_dependencia):
"""Testa método com dependência externa mockada."""
# Arrange
mock_dependencia.return_value = "valor_mock"
instancia = ExemploClasse("parametro")
# Act
resultado = instancia.metodo_com_dependencia()
# Assert
assert resultado == "valor_processado"
mock_dependencia.assert_called_once()
def test_metodo_erro(self):
"""Testa tratamento de erro."""
# Arrange
instancia = ExemploClasse("parametro_invalido")
# Act & Assert
with pytest.raises(ValueError) as exc_info:
instancia.metodo_que_falha()
assert "mensagem esperada" in str(exc_info.value)- Nomenclatura: Use nomes descritivos (
test_funcao_cenario_resultado) - Arrange-Act-Assert: Organize testes com essa estrutura
- Mocks: Use mocks para isolar dependências externas
- Fixtures: Reutilize fixtures para dados comuns
- Documentação: Documente testes complexos
- Cobertura: Mantenha cobertura acima de 70%
import pytest
@pytest.mark.asyncio
async def test_funcao_async():
"""Testa função assíncrona."""
resultado = await funcao_async()
assert resultado == "esperado"@pytest.mark.parametrize("entrada,esperado", [
("PETR4.SA", True),
("INVALID.SA", False),
("", False),
])
def test_validacao_ticker(entrada, esperado):
"""Testa validação de ticker com múltiplos valores."""
resultado = validar_ticker(entrada)
assert resultado == esperadoApós executar testes com cobertura:
# Relatório no terminal
python scripts/run_tests.py --coverage
# Relatório HTML (abra htmlcov/index.html no navegador)
open htmlcov/index.html- Mínimo: 70%
- Recomendado: 80%+
- Ideal: 90%+
O projeto usa GitHub Actions para executar testes automaticamente:
- Push/PR: Executa linting, type checking e testes
- Cobertura: Envia relatórios para Codecov
- Múltiplas versões: Testa com Python 3.12
Configure hooks para executar antes de commits:
pip install pre-commit
pre-commit install# Com breakpoints
uv run pytest --pdb
# Verbose com output
uv run pytest -v -s
# Apenas testes que falharam
uv run pytest --lfimport logging
def test_com_logs(caplog):
"""Testa captura de logs."""
with caplog.at_level(logging.INFO):
funcao_que_loga()
assert "mensagem esperada" in caplog.text- Imports falhando: Verifique se está executando do diretório raiz
- Mocks não funcionando: Verifique o caminho do patch
- Fixtures não encontradas: Verifique se estão em
conftest.py - Testes lentos: Use marcador
@pytest.mark.slow
# Identificar testes mais lentos
uv run pytest --durations=10
# Executar em paralelo
uv run pytest -n auto- Escreva testes para novas funcionalidades
- Mantenha cobertura acima de 70%
- Use fixtures existentes quando possível
- Documente testes complexos
- Execute todos os checks antes de fazer commit
# Antes de fazer commit
python scripts/run_tests.py --all