teste / tests /README.md
torxyton's picture
feat: Implementa estrutura completa de testes com pytest
b9c68d4
# Test Suite Documentation
Este diretório contém a suíte completa de testes para o projeto Hugging Face Spaces. O sistema de testes foi projetado seguindo as melhores práticas de desenvolvimento Python, utilizando pytest como framework principal.
## 📁 Estrutura de Testes
```
tests/
├── README.md # Esta documentação
├── conftest.py # Configurações globais e fixtures
├── test_patterns.py # Exemplos de padrões de teste
├── data/ # Dados de teste
│ └── sample_market_data.json # Dados de mercado para testes
├── unit/ # Testes unitários
│ ├── conftest.py # Fixtures específicas para testes unitários
│ ├── test_advanced_market_processing.py
│ └── test_voting_system.py
└── integration/ # Testes de integração
├── conftest.py # Fixtures específicas para testes de integração
└── test_market_analysis_integration.py
```
## 🚀 Como Executar os Testes
### Usando o Makefile (Recomendado)
```bash
# Executar todos os testes
make test
# Executar apenas testes unitários
make test-unit
# Executar apenas testes de integração
make test-integration
# Executar testes com relatório de cobertura
make test-coverage
# Executar apenas testes rápidos (excluir testes lentos)
make test-fast
# Executar testes em paralelo
make test-parallel
# Executar testes em modo debug
make test-debug
```
### Usando pytest diretamente
```bash
# Executar todos os testes
pytest -v
# Executar testes específicos por marcador
pytest -m unit # Apenas testes unitários
pytest -m integration # Apenas testes de integração
pytest -m "not slow" # Excluir testes lentos
pytest -m performance # Apenas testes de performance
# Executar testes com cobertura
pytest --cov=src --cov-report=html
# Executar testes em paralelo
pytest -n auto
# Executar testes específicos
pytest tests/unit/test_voting_system.py::test_majority_voting
```
## 🏷️ Marcadores de Teste
O sistema utiliza marcadores para categorizar e filtrar testes:
- `unit`: Testes unitários
- `integration`: Testes de integração
- `slow`: Testes que demoram mais para executar
- `api`: Testes de API
- `ui`: Testes de interface do usuário
- `smoke`: Testes de fumaça (básicos)
- `regression`: Testes de regressão
- `performance`: Testes de performance
- `security`: Testes de segurança
### Exemplo de uso de marcadores:
```python
import pytest
@pytest.mark.unit
def test_basic_functionality():
assert True
@pytest.mark.slow
@pytest.mark.performance
def test_large_dataset_processing():
# Teste que demora mais tempo
pass
@pytest.mark.integration
@pytest.mark.api
def test_api_integration():
# Teste de integração com API
pass
```
## 🔧 Configuração
### pytest.ini
O arquivo `pytest.ini` na raiz do projeto contém as configurações principais:
- Descoberta automática de testes
- Configuração de relatórios de cobertura
- Definição de marcadores
- Configuração de timeout
- Filtros de warnings
### conftest.py
Cada nível possui seu próprio `conftest.py`:
- **Global** (`tests/conftest.py`): Fixtures compartilhadas por todos os testes
- **Unit** (`tests/unit/conftest.py`): Fixtures específicas para testes unitários
- **Integration** (`tests/integration/conftest.py`): Fixtures para testes de integração
## 📊 Fixtures Disponíveis
### Fixtures Globais
- `project_root`: Caminho para a raiz do projeto
- `test_data`: Dados de teste carregados
- `temp_dir`: Diretório temporário para testes
- `mock_db`: Mock do banco de dados
- `sample_market_data`: Dados de mercado de exemplo
- `mock_gradio_interface`: Mock da interface Gradio
- `mock_transformers`: Mock da biblioteca transformers
- `test_env_vars`: Variáveis de ambiente para testes
- `caplog_setup`: Configuração de captura de logs
### Fixtures de Testes Unitários
- `mock_logger`: Mock do sistema de logging
- `mock_config`: Mock da configuração
- `mock_market_processor`: Mock do processador de mercado
- `mock_voting_strategy`: Mock da estratégia de votação
- `mock_sentiment_analyzer`: Mock do analisador de sentimento
- `mock_fibonacci_analyzer`: Mock do analisador de Fibonacci
- `sample_price_data`: Dados de preço para testes
- `mock_database_logger`: Mock do logger de banco de dados
### Fixtures de Testes de Integração
- `temp_db`: Banco de dados SQLite temporário
- `db_connection`: Conexão com banco de dados de teste
- `populated_db`: Banco de dados populado com dados de teste
- `mock_yfinance`: Mock da API yfinance
- `mock_requests`: Mock da biblioteca requests
- `integration_config`: Configuração para testes de integração
- `temp_cache_dir`: Diretório de cache temporário
## 📈 Relatórios de Cobertura
Os relatórios de cobertura são gerados em múltiplos formatos:
- **HTML**: `htmlcov/index.html` - Relatório visual detalhado
- **XML**: `coverage.xml` - Para integração com CI/CD
- **Terminal**: Exibido diretamente no terminal
### Visualizar relatório HTML:
```bash
# Gerar e abrir relatório
make test-coverage
open htmlcov/index.html # macOS
start htmlcov/index.html # Windows
```
## 🔍 Padrões de Teste
O arquivo `test_patterns.py` demonstra padrões e melhores práticas:
### 1. Testes Unitários Básicos
```python
def test_basic_functionality():
"""Teste básico de funcionalidade."""
result = some_function()
assert result is not None
assert isinstance(result, expected_type)
```
### 2. Uso de Fixtures
```python
def test_with_fixture(sample_data):
"""Teste usando fixture."""
processor = DataProcessor()
result = processor.process(sample_data)
assert result.is_valid
```
### 3. Mocking
```python
@patch('module.external_service')
def test_with_mock(mock_service):
"""Teste com mock de serviço externo."""
mock_service.return_value = expected_response
result = function_that_uses_service()
assert result == expected_result
mock_service.assert_called_once()
```
### 4. Testes Parametrizados
```python
@pytest.mark.parametrize("input_value,expected", [
(1, 2),
(2, 4),
(3, 6),
])
def test_multiplication(input_value, expected):
"""Teste parametrizado."""
assert multiply_by_two(input_value) == expected
```
### 5. Tratamento de Exceções
```python
def test_exception_handling():
"""Teste de tratamento de exceções."""
with pytest.raises(ValueError, match="Invalid input"):
function_that_should_raise(invalid_input)
```
### 6. Testes Assíncronos
```python
@pytest.mark.asyncio
async def test_async_function():
"""Teste de função assíncrona."""
result = await async_function()
assert result is not None
```
## 🚀 Performance e Benchmarking
### Testes de Performance
```python
@pytest.mark.performance
def test_performance_benchmark(benchmark):
"""Teste de benchmark de performance."""
result = benchmark(expensive_function, large_dataset)
assert result is not None
```
### Monitoramento de Memória
```python
@pytest.mark.performance
def test_memory_usage():
"""Teste de uso de memória."""
import psutil
import os
process = psutil.Process(os.getpid())
initial_memory = process.memory_info().rss
# Executar operação que consome memória
result = memory_intensive_operation()
final_memory = process.memory_info().rss
memory_increase = final_memory - initial_memory
# Verificar se o aumento de memória está dentro do esperado
assert memory_increase < 100 * 1024 * 1024 # 100MB
```
## 🔒 Testes de Segurança
```python
@pytest.mark.security
def test_input_validation():
"""Teste de validação de entrada."""
malicious_inputs = [
"<script>alert('xss')</script>",
"'; DROP TABLE users; --",
"../../../etc/passwd",
]
for malicious_input in malicious_inputs:
with pytest.raises((ValueError, SecurityError)):
process_user_input(malicious_input)
```
## 📝 Melhores Práticas
### 1. Nomenclatura
- Arquivos de teste: `test_*.py` ou `*_test.py`
- Funções de teste: `test_*`
- Classes de teste: `Test*`
- Fixtures: nomes descritivos sem prefixo `test_`
### 2. Organização
- Um arquivo de teste por módulo
- Agrupar testes relacionados em classes
- Usar fixtures para setup/teardown
- Manter testes independentes
### 3. Assertions
```python
# Bom: específico e claro
assert result.status == "success"
assert len(result.items) == 3
assert result.total > 0
# Evitar: muito genérico
assert result
```
### 4. Documentação
```python
def test_complex_scenario():
"""Teste cenário complexo de processamento de dados.
Este teste verifica se o sistema consegue processar
corretamente um dataset com múltiplas anomalias.
"""
# Given: dados com anomalias
data = create_anomalous_dataset()
# When: processamento é executado
result = processor.process(data)
# Then: anomalias são detectadas e tratadas
assert result.anomalies_detected > 0
assert result.status == "processed_with_warnings"
```
## 🔧 Troubleshooting
### Problemas Comuns
1. **Testes lentos**: Use marcador `@pytest.mark.slow` e execute com `make test-fast`
2. **Falhas intermitentes**: Verifique dependências externas e use mocks
3. **Problemas de importação**: Verifique `sys.path` no `conftest.py`
4. **Fixtures não encontradas**: Verifique se estão no `conftest.py` correto
### Debug de Testes
```bash
# Executar com output detalhado
pytest -v -s
# Executar com debugger
pytest --pdb
# Executar teste específico com debug
pytest tests/unit/test_module.py::test_function -v -s --pdb
```
### Logs durante Testes
```python
import logging
def test_with_logging(caplog):
"""Teste com captura de logs."""
with caplog.at_level(logging.INFO):
function_that_logs()
assert "Expected log message" in caplog.text
assert caplog.records[0].levelname == "INFO"
```
## 📚 Recursos Adicionais
- [Documentação do pytest](https://docs.pytest.org/)
- [pytest-cov](https://pytest-cov.readthedocs.io/)
- [pytest-mock](https://pytest-mock.readthedocs.io/)
- [pytest-benchmark](https://pytest-benchmark.readthedocs.io/)
- [Factory Boy](https://factoryboy.readthedocs.io/)
- [Faker](https://faker.readthedocs.io/)
## 🤝 Contribuindo
Ao adicionar novos testes:
1. Siga os padrões estabelecidos
2. Adicione marcadores apropriados
3. Documente testes complexos
4. Mantenha cobertura > 80%
5. Execute `make pre-commit` antes de commitar
---
**Nota**: Esta documentação é mantida junto com o código. Mantenha-a atualizada conforme o sistema evolui.