diff --git a/Back-End/.gitignore b/Back-End/.gitignore index 4a10846..76c85a5 100644 --- a/Back-End/.gitignore +++ b/Back-End/.gitignore @@ -4,4 +4,6 @@ documents data *.dmp staticfiles -/*/Configuration/application*.json \ No newline at end of file +/*/Configuration/application*.json +rapport_tests_back.json +tests_automatiques.json \ No newline at end of file diff --git a/Back-End/requirements.txt b/Back-End/requirements.txt index c930b58..e3b164b 100644 --- a/Back-End/requirements.txt +++ b/Back-End/requirements.txt @@ -70,3 +70,7 @@ xhtml2pdf==0.2.16 channels==4.0.0 channels-redis==4.1.0 daphne==4.1.0 +pytest +djangorestframework +pytest-django +pytest-json-report diff --git a/Back-End/test_all_endpoints.py b/Back-End/test_all_endpoints.py new file mode 100644 index 0000000..6b3aea7 --- /dev/null +++ b/Back-End/test_all_endpoints.py @@ -0,0 +1,39 @@ +""" +Starter de tests automatiques pour valider tous les endpoints définis dans les fichiers urls.py du projet Django N3WT-SCHOOL. +Chaque endpoint est testé pour la réponse HTTP attendue (200, 401, 403, 404, etc.). +""" +import pytest +from django.urls import reverse, resolve +from rest_framework.test import APIClient +from django.conf import settings +from django.urls import get_resolver + +@pytest.mark.django_db +class TestAllEndpoints: + @pytest.fixture(autouse=True) + def setup(self): + self.client = APIClient() + + def get_all_url_patterns(self): + resolver = get_resolver() + patterns = resolver.url_patterns + urls = [] + def extract(patterns, prefix=""): + for p in patterns: + if hasattr(p, 'url_patterns'): + extract(p.url_patterns, prefix + str(p.pattern)) + else: + urls.append(prefix + str(p.pattern)) + extract(patterns) + return urls + + def test_all_endpoints_anonymous(self): + urls = self.get_all_url_patterns() + for url in urls: + if '<' in url: # skip dynamic urls for starter + continue + try: + response = self.client.get(url) + assert response.status_code in [200, 401, 403, 404] + except Exception as e: + print(f"Erreur sur {url}: {e}") diff --git a/Back-End/test_auth_endpoints.py b/Back-End/test_auth_endpoints.py new file mode 100644 index 0000000..1f63c6e --- /dev/null +++ b/Back-End/test_auth_endpoints.py @@ -0,0 +1,124 @@ +""" +Tests automatiques pour les endpoints Auth de l'API N3WT-SCHOOL. +- Teste les endpoints GET, y compris dynamiques. +- Teste l'authentification (login JWT) et l'accès aux endpoints protégés. +- Vérifie la structure JSON des réponses principales. +""" +import pytest +from django.urls import reverse +from rest_framework.test import APIClient +from Auth.models import Profile, ProfileRole +from Establishment.models import Establishment +from django.contrib.auth.hashers import make_password + +@pytest.mark.django_db +class TestAuthEndpoints: + @pytest.fixture(autouse=True) + def setup(self, db): + self.client = APIClient() + # Création d'un établissement de test + self.establishment = Establishment.objects.create( + name="Etablissement Test", + address="1 rue du test", + total_capacity=100, + establishment_type=[1], + evaluation_frequency=1, + licence_code="LIC123", + is_active=True + ) + # Création d'un utilisateur de test + self.test_email = 'testuser@example.com' + self.test_password = 'testpass123' + self.profile = Profile.objects.create( + email=self.test_email, + username=self.test_email, + password=make_password(self.test_password) + ) + self.profile_role = ProfileRole.objects.create( + profile=self.profile, + role_type=1, # ADMIN + establishment=self.establishment, + is_active=True + ) + + def test_csrf(self): + response = self.client.get('/Auth/csrf') + assert response.status_code == 200 + assert 'csrfToken' in response.json() + + def test_login(self): + response = self.client.post('/Auth/login', { + 'email': self.test_email, + 'password': self.test_password + }, format='json') + assert response.status_code in [200, 401] + if response.status_code == 200: + assert 'access' in response.json() or 'token' in response.json() + + def test_profiles(self): + # GET /Auth/profiles + response = self.client.get(f'/Auth/profiles') + assert response.status_code in [200, 401, 403] + if response.status_code == 200: + # Vérifie que le profil de test existe dans la liste + emails = [p.get('email') for p in response.json() if isinstance(p, dict)] + assert self.test_email in emails + + def test_profiles_id(self): + # GET /Auth/profiles/ + response = self.client.get(f'/Auth/profiles/{self.profile.id}') + assert response.status_code in [200, 401, 403, 404] + if response.status_code == 200: + data = response.json() + assert data.get('email') == self.test_email + + def test_profile_roles(self): + # GET /Auth/profileRoles avec paramètres requis + params = { + 'establishment_id': self.establishment.id, + 'filter': 'school' + } + response = self.client.get('/Auth/profileRoles', params) + assert response.status_code in [200, 401, 403, 400] + if response.status_code == 200: + results = response.json() + # Adapter à la structure réelle de la réponse : clé 'profilesRoles' + if isinstance(results, dict) and 'profilesRoles' in results: + results = results['profilesRoles'] + found = any( + r.get('profile') == self.profile.id and r.get('role_type') == 1 + for r in results if isinstance(r, dict) + ) + assert found + + def test_profile_roles_id(self): + # GET /Auth/profileRoles/ + response = self.client.get(f'/Auth/profileRoles/{self.profile_role.id}') + assert response.status_code in [200, 401, 403, 404] + if response.status_code == 200: + data = response.json() + assert data.get('profile') == self.profile.id + assert data.get('role_type') == 1 + + def test_reset_password(self): + # POST /Auth/resetPassword/ (méthode attendue) + response = self.client.post('/Auth/resetPassword/ABCDEF', { + 'password1': 'newpass123', + 'password2': 'newpass123' + }, format='json') + assert response.status_code in [200, 400, 404] + # 400 attendu si le code est invalide ou expiré + + def test_info_session(self): + # GET /Auth/infoSession (protégé) + login = self.client.post('/Auth/login', { + 'email': self.test_email, + 'password': self.test_password + }, format='json') + if login.status_code == 200 and ('access' in login.json() or 'token' in login.json()): + token = login.json().get('access') or login.json().get('token') + self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {token}') + response = self.client.get('/Auth/infoSession') + assert response.status_code in [200, 401, 403] + else: + pytest.skip('Impossible de s’authentifier pour tester infoSession') diff --git a/docs/tests_automatiques.md b/docs/tests_automatiques.md new file mode 100644 index 0000000..3f57adc --- /dev/null +++ b/docs/tests_automatiques.md @@ -0,0 +1,59 @@ +# Documentation des tests automatiques + +Ce document décrit la structure et l’utilisation du starter de tests automatiques pour valider tous les endpoints exposés par les fichiers `urls.py` des applications Django du Back-End. + +## Objectif + +- Vérifier automatiquement que chaque route définie dans le projet répond bien à une requête HTTP (statut attendu : 200, 401, 403, 404). +- Permettre une validation rapide de la couverture des endpoints lors de chaque pipeline CI. + +## Structure + +- Le fichier principal est `Back-End/test_all_endpoints.py`. +- Ce test utilise `pytest` et `pytest-django` pour parcourir toutes les routes du projet et effectuer une requête GET anonyme. +- Les routes dynamiques (avec paramètres) sont ignorées dans ce starter. + +## Exécution + +1. Installer les dépendances si besoin : + ```sh + pip install pytest pytest-django djangorestframework + ``` +2. Lancer les tests : + ```sh + pytest Back-End/test_all_endpoints.py + ``` + +## Intégration CI + +- Ajouter la commande de test dans votre pipeline CI (GitHub Actions, GitLab CI, Jenkins, etc.) : + ```sh + pytest Back-End/test_all_endpoints.py + ``` + +## Personnalisation + +- Pour tester les routes nécessitant une authentification ou des paramètres, compléter le test avec des cas spécifiques. +- Pour chaque nouvelle route, le test s’exécutera automatiquement. + +## Ajout + +- Ajout d'un fichier de tests automatiques dédié à Auth (`test_auth_endpoints.py`) pour tester tous les endpoints Auth (GET, dynamiques, login JWT, accès protégé, structure JSON). +- Les tests créent un utilisateur et un profilRole de test, réalisent un login, et vérifient les accès aux endpoints principaux, y compris les routes dynamiques et protégées. + +## Utilisation + +- Lancer les tests avec : + ```bash + pytest --json-report --json-report-file=tests_automatiques.json + ``` +- Le rapport inclura les résultats détaillés pour chaque endpoint Auth. + +## Extension + +- Étendre sur le même modèle pour les autres applications (School, Subscriptions, etc.) +- Ajouter des tests POST/PUT/DELETE et des cas d’erreur/permissions. + +--- + +Pour toute question ou évolution, se référer au ticket associé.