Some checks failed
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
205 lines
5.0 KiB
Markdown
205 lines
5.0 KiB
Markdown
# 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_<module>.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/<name>.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_<action>_<condition>_<expected_result>`
|