# Tests - Homelab Automation Dashboard Architecture de tests complète pour le backend FastAPI et le frontend JavaScript. ## Structure ``` tests/ ├── backend/ # Tests Python (pytest) │ ├── conftest.py # Fixtures partagées (DB, client, mocks) │ ├── test_routes_auth.py # Tests authentification JWT │ ├── test_routes_hosts.py # Tests CRUD hôtes │ ├── test_routes_schedules.py # Tests planificateur │ ├── test_services_ansible.py # Tests service Ansible │ ├── test_services_scheduler.py # Tests APScheduler │ ├── test_services_notification.py # Tests ntfy │ └── test_websocket.py # Tests WebSocket ├── frontend/ # Tests JavaScript (Vitest) │ ├── setup.js # Configuration (mocks fetch, WS, localStorage) │ ├── main.test.js # Tests DashboardManager │ └── dom.test.js # Tests rendu DOM └── README.md # Ce fichier ``` ## Prérequis ### Backend (Python) ```bash pip install pytest pytest-asyncio pytest-cov httpx respx freezegun pytest-mock ``` ### Frontend (Node.js) ```bash sudo apt-get install nodejs npm npm install ``` ## Commandes ### Exécuter tous les tests ```bash make test-all # Ou avec coverage: make test-cov # Ou séparément: make test-backend make test-frontend ``` ### Avec couverture ```bash make test-cov ``` ### Mode watch (développement) ```bash make test-watch # Frontend Vitest watch pytest-watch tests/backend # Backend (nécessite pytest-watch) ``` ### Tests rapides ```bash make test-quick ``` ### Tests backend uniquement ```bash pytest tests/backend -v -m "unit" # Avec coverage: pytest tests/backend --cov=app --cov-report=html ``` ### Tests frontend uniquement ```bash npm test # Avec coverage: npm run test:coverage ``` ## Marqueurs pytest | Marqueur | Description | |----------|-------------| | `@pytest.mark.unit` | Tests unitaires (rapides, isolés) | | `@pytest.mark.integration` | Tests d'intégration | | `@pytest.mark.slow` | Tests lents (skippés en CI fast) | Exécuter par marqueur: ```bash pytest tests/backend -m "unit" pytest tests/backend -m "integration" pytest tests/backend -m "not slow" ``` ## Fixtures Principales (Backend) ### `db_session` Session SQLAlchemy async avec SQLite in-memory. Rollback automatique après chaque test. ### `client` AsyncClient httpx avec authentification mockée. Dépendances FastAPI overridées. ### `unauthenticated_client` AsyncClient sans authentification pour tester les erreurs 401. ### `mock_ansible_service` Mock complet du service Ansible (pas de subprocess réel). ### `mock_notification_service` Mock du service ntfy (pas de HTTP réel). ### `host_factory`, `user_factory`, etc. Factories pour créer des données de test. ```python async def test_example(db_session, host_factory): host = await host_factory.create(db_session, name="test.local") assert host.name == "test.local" ``` ## Mocks Frontend ### `setupFetchMock(responses)` Configure les réponses fetch mockées: ```javascript setupFetchMock({ '/api/hosts': [{ id: 'h1', name: 'server1' }], '/api/auth/status': { authenticated: true } }); ``` ### `MockWebSocket` Classe WebSocket mockée avec helpers: ```javascript const ws = new MockWebSocket('ws://localhost/ws'); ws._receiveMessage({ type: 'host_updated', data: {...} }); ``` ### `localStorageMock` Mock localStorage avec espions: ```javascript expect(localStorageMock.setItem).toHaveBeenCalledWith('accessToken', 'token'); ``` ## Ajouter un Nouveau Test ### Backend 1. Créer le fichier `tests/backend/test_.py` 2. Importer les fixtures depuis `conftest.py` 3. Utiliser les marqueurs appropriés ```python import pytest from httpx import AsyncClient pytestmark = [pytest.mark.unit, pytest.mark.asyncio] class TestMyFeature: async def test_something(self, client: AsyncClient, db_session): response = await client.get("/api/my-endpoint") assert response.status_code == 200 ``` ### Frontend 1. Créer le fichier `tests/frontend/.test.js` 2. Importer les utilitaires depuis `setup.js` ```javascript import { describe, it, expect } from 'vitest'; import { setupFetchMock } from './setup.js'; describe('MyFeature', () => { it('does something', async () => { setupFetchMock({ '/api/data': { value: 42 } }); // Test... }); }); ``` ## Seuils de Couverture | Composant | Seuil | |-----------|-------| | Backend global | 80% | | Services critiques | 90% | | Frontend global | 60% | ## CI/CD Les tests s'exécutent automatiquement via GitHub Actions sur: - Push sur `main` ou `develop` - Pull requests vers `main` ou `develop` Voir `.github/workflows/tests.yml` ## Bonnes Pratiques 1. **Isolation**: Chaque test est indépendant (DB rollback, mocks reset) 2. **Pas de réseau**: Tous les appels HTTP/SSH sont mockés 3. **Déterminisme**: Utiliser `freezegun` pour les tests liés au temps 4. **AAA Pattern**: Arrange, Act, Assert clairement séparés 5. **Nommage explicite**: `test___`