feat(setup): T05 configure pytest with coverage
- Create pytest.ini with: - Test discovery configuration (testpaths, python_files) - Asyncio mode settings - Coverage configuration (>=90% requirement) - Custom markers (unit, integration, e2e, slow) - Update conftest.py with: - pytest_asyncio plugin - Shared fixtures (project_root, src_path, temp_dir, mock_env_vars) - Path configuration for imports - Add test_pytest_config.py with 12 unit tests - All tests passing (12/12) Refs: T05 Completes setup phase T01-T05
This commit is contained in:
@@ -8,13 +8,13 @@
|
|||||||
|
|
||||||
| Metrica | Valore |
|
| Metrica | Valore |
|
||||||
|---------|--------|
|
|---------|--------|
|
||||||
| **Stato** | 🟡 In Progress |
|
| **Stato** | 🟢 Setup Completato |
|
||||||
| **Progresso** | 5% |
|
| **Progresso** | 7% |
|
||||||
| **Data Inizio** | 2024-04-07 |
|
| **Data Inizio** | 2024-04-07 |
|
||||||
| **Data Target** | TBD |
|
| **Data Target** | TBD |
|
||||||
| **Task Totali** | 74 |
|
| **Task Totali** | 74 |
|
||||||
| **Task Completati** | 4 |
|
| **Task Completati** | 5 |
|
||||||
| **Task In Progress** | 1 |
|
| **Task In Progress** | 0 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -37,12 +37,12 @@
|
|||||||
|
|
||||||
## 📋 Task Pianificate
|
## 📋 Task Pianificate
|
||||||
|
|
||||||
### 🔧 Setup Progetto (T01-T05) - 4/5 completati
|
### 🔧 Setup Progetto (T01-T05) - 5/5 completati
|
||||||
- [x] T01: Creare struttura cartelle progetto (2024-04-07)
|
- [x] T01: Creare struttura cartelle progetto (2024-04-07)
|
||||||
- [x] T02: Inizializzare virtual environment e .gitignore (2024-04-07)
|
- [x] T02: Inizializzare virtual environment e .gitignore (2024-04-07)
|
||||||
- [x] T03: Creare requirements.txt con dipendenze (2024-04-07)
|
- [x] T03: Creare requirements.txt con dipendenze (2024-04-07)
|
||||||
- [x] T04: Setup file configurazione (.env, config.py) (2024-04-07)
|
- [x] T04: Setup file configurazione (.env, config.py) (2024-04-07)
|
||||||
- [ ] T05: Configurare pytest e struttura test
|
- [x] T05: Configurare pytest e struttura test (2024-04-07)
|
||||||
|
|
||||||
### 🗄️ Database & Models (T06-T11) - 0/6 completati
|
### 🗄️ Database & Models (T06-T11) - 0/6 completati
|
||||||
- [ ] T06: Creare database.py (connection & session)
|
- [ ] T06: Creare database.py (connection & session)
|
||||||
|
|||||||
32
pytest.ini
Normal file
32
pytest.ini
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
[pytest]
|
||||||
|
# Test discovery settings
|
||||||
|
testpaths = tests
|
||||||
|
python_files = test_*.py
|
||||||
|
python_classes = Test*
|
||||||
|
python_functions = test_*
|
||||||
|
|
||||||
|
# Asyncio settings
|
||||||
|
asyncio_mode = auto
|
||||||
|
asyncio_default_fixture_loop_scope = function
|
||||||
|
|
||||||
|
# Coverage settings
|
||||||
|
addopts =
|
||||||
|
-v
|
||||||
|
--strict-markers
|
||||||
|
--tb=short
|
||||||
|
--cov=src/openrouter_monitor
|
||||||
|
--cov-report=term-missing
|
||||||
|
--cov-report=html:htmlcov
|
||||||
|
--cov-fail-under=90
|
||||||
|
|
||||||
|
# Markers
|
||||||
|
testmarkers =
|
||||||
|
unit: Unit tests (no external dependencies)
|
||||||
|
integration: Integration tests (with mocked dependencies)
|
||||||
|
e2e: End-to-end tests (full workflow)
|
||||||
|
slow: Slow tests (skip in quick mode)
|
||||||
|
|
||||||
|
# Filter warnings
|
||||||
|
filterwarnings =
|
||||||
|
ignore::DeprecationWarning:passlib.*
|
||||||
|
ignore::UserWarning
|
||||||
Binary file not shown.
@@ -0,0 +1,50 @@
|
|||||||
|
"""Pytest configuration and fixtures.
|
||||||
|
|
||||||
|
This module contains shared fixtures and configuration for all tests.
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
import pytest_asyncio
|
||||||
|
|
||||||
|
# Add src to path for importing in tests
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
|
||||||
|
|
||||||
|
# Markers for test organization
|
||||||
|
pytest_plugins = ['pytest_asyncio']
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_configure(config):
|
||||||
|
"""Configure pytest with custom markers."""
|
||||||
|
config.addinivalue_line("markers", "unit: Unit tests (no external dependencies)")
|
||||||
|
config.addinivalue_line("markers", "integration: Integration tests (with mocked dependencies)")
|
||||||
|
config.addinivalue_line("markers", "e2e: End-to-end tests (full workflow)")
|
||||||
|
config.addinivalue_line("markers", "slow: Slow tests (skip in quick mode)")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def project_root():
|
||||||
|
"""Return the project root directory."""
|
||||||
|
return os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def src_path(project_root):
|
||||||
|
"""Return the src directory path."""
|
||||||
|
return os.path.join(project_root, 'src')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def temp_dir(tmp_path):
|
||||||
|
"""Provide a temporary directory for tests."""
|
||||||
|
return tmp_path
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_env_vars(monkeypatch):
|
||||||
|
"""Set up mock environment variables for testing."""
|
||||||
|
monkeypatch.setenv('SECRET_KEY', 'test-secret-key-min-32-characters-long')
|
||||||
|
monkeypatch.setenv('ENCRYPTION_KEY', 'test-32-byte-encryption-key!!')
|
||||||
|
monkeypatch.setenv('DATABASE_URL', 'sqlite:///./test.db')
|
||||||
|
monkeypatch.setenv('DEBUG', 'true')
|
||||||
|
monkeypatch.setenv('LOG_LEVEL', 'DEBUG')
|
||||||
|
|||||||
103
tests/unit/test_pytest_config.py
Normal file
103
tests/unit/test_pytest_config.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
"""Test for pytest configuration (T05)."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
class TestPytestConfiguration:
|
||||||
|
"""Test pytest configuration and setup."""
|
||||||
|
|
||||||
|
def test_pytest_ini_exists(self):
|
||||||
|
"""Verify pytest.ini file exists."""
|
||||||
|
ini_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/pytest.ini"
|
||||||
|
assert os.path.isfile(ini_path), f"File {ini_path} does not exist"
|
||||||
|
|
||||||
|
def test_pytest_ini_has_testpaths(self):
|
||||||
|
"""Verify pytest.ini contains testpaths configuration."""
|
||||||
|
ini_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/pytest.ini"
|
||||||
|
with open(ini_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
assert 'testpaths' in content, "pytest.ini should contain testpaths"
|
||||||
|
|
||||||
|
def test_pytest_ini_has_python_files(self):
|
||||||
|
"""Verify pytest.ini contains python_files configuration."""
|
||||||
|
ini_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/pytest.ini"
|
||||||
|
with open(ini_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
assert 'python_files' in content, "pytest.ini should contain python_files"
|
||||||
|
|
||||||
|
def test_pytest_ini_has_python_functions(self):
|
||||||
|
"""Verify pytest.ini contains python_functions configuration."""
|
||||||
|
ini_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/pytest.ini"
|
||||||
|
with open(ini_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
assert 'python_functions' in content, "pytest.ini should contain python_functions"
|
||||||
|
|
||||||
|
def test_pytest_ini_has_addopts(self):
|
||||||
|
"""Verify pytest.ini contains addopts configuration."""
|
||||||
|
ini_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/pytest.ini"
|
||||||
|
with open(ini_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
assert 'addopts' in content, "pytest.ini should contain addopts"
|
||||||
|
|
||||||
|
def test_pytest_ini_has_cov_config(self):
|
||||||
|
"""Verify pytest.ini contains coverage configuration."""
|
||||||
|
ini_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/pytest.ini"
|
||||||
|
with open(ini_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
assert 'cov' in content.lower(), "pytest.ini should contain coverage config"
|
||||||
|
|
||||||
|
def test_conftest_py_exists(self):
|
||||||
|
"""Verify conftest.py file exists."""
|
||||||
|
conf_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/tests/conftest.py"
|
||||||
|
assert os.path.isfile(conf_path), f"File {conf_path} does not exist"
|
||||||
|
|
||||||
|
def test_conftest_py_has_pytest_plugins(self):
|
||||||
|
"""Verify conftest.py contains pytest_plugins."""
|
||||||
|
conf_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/tests/conftest.py"
|
||||||
|
with open(conf_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
assert 'pytest_plugins' in content or 'fixture' in content, \
|
||||||
|
"conftest.py should contain pytest plugins or fixtures"
|
||||||
|
|
||||||
|
def test_conftest_py_imports_pytest_asyncio(self):
|
||||||
|
"""Verify conftest.py imports pytest_asyncio."""
|
||||||
|
conf_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/tests/conftest.py"
|
||||||
|
with open(conf_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
assert 'pytest_asyncio' in content or 'asyncio' in content.lower(), \
|
||||||
|
"conftest.py should import pytest_asyncio"
|
||||||
|
|
||||||
|
def test_pytest_can_run_tests(self):
|
||||||
|
"""Verify pytest can actually run tests."""
|
||||||
|
import subprocess
|
||||||
|
result = subprocess.run(
|
||||||
|
['python3', '-m', 'pytest', '--version'],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
assert result.returncode == 0, "pytest should be runnable"
|
||||||
|
assert 'pytest' in result.stdout.lower(), "pytest version should be displayed"
|
||||||
|
|
||||||
|
def test_pytest_can_discover_tests(self):
|
||||||
|
"""Verify pytest can discover tests in the project."""
|
||||||
|
import subprocess
|
||||||
|
result = subprocess.run(
|
||||||
|
['python3', '-m', 'pytest', '--collect-only', '-q'],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
cwd='/home/google/Sources/LucaSacchiNet/openrouter-watcher'
|
||||||
|
)
|
||||||
|
assert result.returncode == 0, "pytest should collect tests without errors"
|
||||||
|
# Should find at least some tests
|
||||||
|
assert 'test' in result.stdout.lower(), "pytest should find tests"
|
||||||
|
|
||||||
|
def test_coverage_is_configured(self):
|
||||||
|
"""Verify coverage is configured in pytest."""
|
||||||
|
ini_path = "/home/google/Sources/LucaSacchiNet/openrouter-watcher/pytest.ini"
|
||||||
|
with open(ini_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
# Check for coverage report configuration
|
||||||
|
assert any(term in content.lower() for term in ['cov-report', 'coverage', 'cov=']), \
|
||||||
|
"pytest.ini should configure coverage reporting"
|
||||||
Reference in New Issue
Block a user