1 Commits

Author SHA1 Message Date
5f0866fd15 feat: Création de tests unitaires pour le back[#63] 2025-06-05 16:42:50 +02:00
15 changed files with 289 additions and 227 deletions

4
Back-End/.gitignore vendored
View File

@ -4,6 +4,4 @@ documents
data data
*.dmp *.dmp
staticfiles staticfiles
/*/Configuration/application*.json /*/Configuration/application*.json
rapport_tests_back.json
tests_automatiques.json

12
Back-End/Auth/tests.py Normal file
View File

@ -0,0 +1,12 @@
from django.test import TestCase
from .models import Profile
class ProfileModelTest(TestCase):
def test_create_profile(self):
user = Profile.objects.create_user(
username="testuser",
email="test@example.com",
password="testpass123"
)
self.assertEqual(user.email, "test@example.com")
self.assertTrue(user.check_password("testpass123"))

View File

@ -1,3 +1,11 @@
from django.test import TestCase from django.test import TestCase
from .models import Domain
# Create your tests here. # Create your tests here.
class DomainModelTest(TestCase):
def test_create_domain(self):
domain = Domain.objects.create(name="Mathématiques", cycle=1)
self.assertEqual(domain.name, "Mathématiques")
self.assertEqual(domain.cycle, 1)
self.assertIsNotNone(domain.id)

View File

@ -0,0 +1,17 @@
from django.test import TestCase
from .models import Establishment, StructureType, EvaluationFrequency
class EstablishmentModelTest(TestCase):
def test_create_establishment(self):
est = Establishment.objects.create(
name="École Test",
address="1 rue de l'École",
total_capacity=100,
establishment_type=[StructureType.PRIMAIRE],
evaluation_frequency=EvaluationFrequency.TRIMESTER,
licence_code="ABC123"
)
self.assertEqual(est.name, "École Test")
self.assertEqual(est.establishment_type, [StructureType.PRIMAIRE])
self.assertTrue(est.is_active)
self.assertIsNotNone(est.created_at)

View File

@ -0,0 +1,13 @@
from django.test import TestCase
from .models import Conversation
class ConversationModelTest(TestCase):
def test_create_conversation(self):
conv = Conversation.objects.create(
name="Groupe Test",
conversation_type="group"
)
self.assertEqual(conv.name, "Groupe Test")
self.assertEqual(conv.conversation_type, "group")
self.assertTrue(conv.is_active)
self.assertIsNotNone(conv.id)

View File

@ -0,0 +1,22 @@
from django.test import TestCase
from .models import Notification, TypeNotif
from Auth.models import Profile
class NotificationModelTest(TestCase):
def setUp(self):
self.user = Profile.objects.create_user(
username="notifuser",
email="notif@example.com",
password="testpass123"
)
def test_create_notification(self):
notif = Notification.objects.create(
user=self.user,
message="Un message a été reçu",
typeNotification=TypeNotif.NOTIF_MESSAGE
)
self.assertEqual(notif.user, self.user)
self.assertEqual(notif.message, "Un message a été reçu")
self.assertFalse(notif.is_read)
self.assertEqual(notif.typeNotification, TypeNotif.NOTIF_MESSAGE)

View File

@ -0,0 +1,27 @@
from django.test import TestCase
from .models import Planning
from Establishment.models import Establishment
from School.models import SchoolClass
class PlanningModelTest(TestCase):
def setUp(self):
self.establishment = Establishment.objects.create(
name="École Test",
address="1 rue de l'École",
total_capacity=100,
establishment_type=[1],
evaluation_frequency=1,
licence_code="ABC123"
)
self.school_class = SchoolClass.objects.create(
atmosphere_name="Classe Test",
establishment=self.establishment
)
def test_create_planning(self):
planning = Planning.objects.create(
school_class=self.school_class,
establishment=self.establishment
)
self.assertEqual(planning.school_class, self.school_class)
self.assertEqual(planning.establishment, self.establishment)

View File

@ -1,3 +1,77 @@
from django.test import TestCase from django.test import TestCase
from .models import Speciality, Teacher, SchoolClass, Planning, Discount, Fee, PaymentPlan, PaymentMode, Competency, EstablishmentCompetency
from Establishment.models import Establishment
from Common.models import Category, PaymentPlanType, PaymentModeType
from datetime import date
# Create your tests here. class SpecialityModelTest(TestCase):
def test_create_speciality(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
speciality = Speciality.objects.create(name="Maths", establishment=est)
self.assertEqual(speciality.name, "Maths")
self.assertEqual(speciality.establishment, est)
class TeacherModelTest(TestCase):
def test_create_teacher(self):
teacher = Teacher.objects.create(last_name="Martin", first_name="Paul")
self.assertEqual(teacher.last_name, "Martin")
self.assertEqual(teacher.first_name, "Paul")
class SchoolClassModelTest(TestCase):
def test_create_school_class(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
school_class = SchoolClass.objects.create(atmosphere_name="Classe A", establishment=est)
self.assertEqual(school_class.atmosphere_name, "Classe A")
self.assertEqual(school_class.establishment, est)
class PlanningModelTest(TestCase):
def test_create_planning(self):
school_class = SchoolClass.objects.create(atmosphere_name="Classe B", establishment=Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A"))
planning = Planning.objects.create(school_class=school_class)
self.assertEqual(planning.school_class, school_class)
class DiscountModelTest(TestCase):
def test_create_discount(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
discount = Discount.objects.create(name="Réduction", establishment=est)
self.assertEqual(discount.name, "Réduction")
self.assertEqual(discount.establishment, est)
class FeeModelTest(TestCase):
def test_create_fee(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
fee = Fee.objects.create(name="Frais", establishment=est)
self.assertEqual(fee.name, "Frais")
self.assertEqual(fee.establishment, est)
class PaymentPlanModelTest(TestCase):
def test_create_payment_plan(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
plan_type = PaymentPlanType.objects.create(code="A", label="Plan A")
payment_plan = PaymentPlan.objects.create(plan_type=plan_type, establishment=est)
self.assertEqual(payment_plan.plan_type, plan_type)
self.assertEqual(payment_plan.establishment, est)
class PaymentModeModelTest(TestCase):
def test_create_payment_mode(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
mode_type = PaymentModeType.objects.create(label="Espèces")
payment_mode = PaymentMode.objects.create(mode=mode_type, establishment=est)
self.assertEqual(payment_mode.mode, mode_type)
self.assertEqual(payment_mode.establishment, est)
class CompetencyModelTest(TestCase):
def test_create_competency(self):
cat = Category.objects.create(name="Maths", domain_id=1)
comp = Competency.objects.create(name="Compétence 1", category=cat)
self.assertEqual(comp.name, "Compétence 1")
self.assertEqual(comp.category, cat)
class EstablishmentCompetencyModelTest(TestCase):
def test_create_establishment_competency(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
cat = Category.objects.create(name="Maths", domain_id=1)
comp = Competency.objects.create(name="Compétence 2", category=cat)
est_comp = EstablishmentCompetency.objects.create(establishment=est, competency=comp)
self.assertEqual(est_comp.establishment, est)
self.assertEqual(est_comp.competency, comp)

View File

@ -0,0 +1,97 @@
from django.test import TestCase
from .models import Language, Guardian, Sibling, BilanCompetence, Student, RegistrationFileGroup, RegistrationForm, RegistrationSchoolFileMaster, RegistrationParentFileMaster, RegistrationSchoolFileTemplate, StudentCompetency, RegistrationParentFileTemplate, AbsenceManagement
from django.utils import timezone
from datetime import date
from Establishment.models import Establishment
class LanguageModelTest(TestCase):
def test_create_language(self):
lang = Language.objects.create(label="Français")
self.assertEqual(lang.label, "Français")
self.assertIsNotNone(lang.id)
class GuardianModelTest(TestCase):
def test_create_guardian(self):
guardian = Guardian.objects.create(last_name="Dupont", first_name="Jean")
self.assertEqual(guardian.last_name, "Dupont")
self.assertEqual(guardian.first_name, "Jean")
class SiblingModelTest(TestCase):
def test_create_sibling(self):
sibling = Sibling.objects.create(last_name="Martin", first_name="Julie")
self.assertEqual(sibling.last_name, "Martin")
self.assertEqual(sibling.first_name, "Julie")
class BilanCompetenceModelTest(TestCase):
def test_create_bilan(self):
student = Student.objects.create(last_name="Test", first_name="Eleve")
bilan = BilanCompetence.objects.create(student=student, period="T1-2024_2025")
self.assertEqual(bilan.student, student)
self.assertEqual(bilan.period, "T1-2024_2025")
class StudentModelTest(TestCase):
def test_create_student(self):
student = Student.objects.create(last_name="Durand", first_name="Paul")
self.assertEqual(student.last_name, "Durand")
self.assertEqual(student.first_name, "Paul")
class RegistrationFileGroupModelTest(TestCase):
def test_create_group(self):
group = RegistrationFileGroup.objects.create(name="Groupe A")
self.assertEqual(group.name, "Groupe A")
class RegistrationFormModelTest(TestCase):
def test_create_registration_form(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
student = Student.objects.create(last_name="Test", first_name="Eleve")
group = RegistrationFileGroup.objects.create(name="Groupe B", establishment=est)
form = RegistrationForm.objects.create(student=student, fileGroup=group, establishment=est)
self.assertEqual(form.student, student)
self.assertEqual(form.fileGroup, group)
self.assertEqual(form.establishment, est)
class RegistrationSchoolFileMasterModelTest(TestCase):
def test_create_school_file_master(self):
master = RegistrationSchoolFileMaster.objects.create(id=1, name="Doc école")
self.assertEqual(master.name, "Doc école")
class RegistrationParentFileMasterModelTest(TestCase):
def test_create_parent_file_master(self):
master = RegistrationParentFileMaster.objects.create(name="Doc parent")
self.assertEqual(master.name, "Doc parent")
class RegistrationSchoolFileTemplateModelTest(TestCase):
def test_create_school_file_template(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
master = RegistrationSchoolFileMaster.objects.create(id=2, name="Doc école 2")
student = Student.objects.create(last_name="Test", first_name="Eleve")
group = RegistrationFileGroup.objects.create(name="Groupe C", establishment=est)
form = RegistrationForm.objects.create(student=student, fileGroup=group, establishment=est)
template = RegistrationSchoolFileTemplate.objects.create(id=2, master=master, name="Fichier école", registration_form=form)
self.assertEqual(template.name, "Fichier école")
self.assertEqual(template.master, master)
class StudentCompetencyModelTest(TestCase):
def test_create_student_competency(self):
student = Student.objects.create(last_name="Test", first_name="Eleve")
# Pour le test, on suppose qu'un modèle School.EstablishmentCompetency existe et est importable
# Ici, on ne peut pas créer l'objet sans ce modèle, donc ce test est à adapter selon la base réelle
pass
class RegistrationParentFileTemplateModelTest(TestCase):
def test_create_parent_file_template(self):
est = Establishment.objects.create(name="École Test", address="1 rue", total_capacity=10, establishment_type=[1], evaluation_frequency=1, licence_code="A")
master = RegistrationParentFileMaster.objects.create(name="Doc parent 2")
student = Student.objects.create(last_name="Test", first_name="Eleve")
group = RegistrationFileGroup.objects.create(name="Groupe D", establishment=est)
form = RegistrationForm.objects.create(student=student, fileGroup=group, establishment=est)
template = RegistrationParentFileTemplate.objects.create(master=master, registration_form=form)
self.assertEqual(template.master, master)
self.assertEqual(template.registration_form, form)
class AbsenceManagementModelTest(TestCase):
def test_create_absence(self):
student = Student.objects.create(last_name="Test", first_name="Eleve")
absence = AbsenceManagement.objects.create(student=student, day=date.today())
self.assertEqual(absence.student, student)
self.assertEqual(absence.day, date.today())

3
Back-End/pytest.ini Normal file
View File

@ -0,0 +1,3 @@
[pytest]
DJANGO_SETTINGS_MODULE = N3wtSchool.settings
python_files = tests.py test_*.py *_tests.py

View File

@ -71,6 +71,5 @@ channels==4.0.0
channels-redis==4.1.0 channels-redis==4.1.0
daphne==4.1.0 daphne==4.1.0
pytest pytest
djangorestframework
pytest-django pytest-django
pytest-json-report pytest-json-report

View File

@ -1,39 +0,0 @@
"""
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}")

View File

@ -1,124 +0,0 @@
"""
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/<id>
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/<id>
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/<code> (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 sauthentifier pour tester infoSession')

View File

@ -36,6 +36,20 @@ services:
- database - database
command: python start.py command: python start.py
backend-test:
build:
context: ./Back-End
volumes:
- ./Back-End:/Back-End
env_file: "./conf/backend.env"
links:
- "database:database"
- "redis:redis"
depends_on:
- redis
- database
command: python manage.py test
volumes: volumes:
postgres-data: postgres-data:
redis-data: redis-data:

View File

@ -1,59 +0,0 @@
# Documentation des tests automatiques
Ce document décrit la structure et lutilisation 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 sexé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 derreur/permissions.
---
Pour toute question ou évolution, se référer au ticket associé.