clean: remove tests
This commit is contained in:
@@ -1,94 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test manuel pour vérifier le bon fonctionnement du système de configuration.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
from models import CompetenceScaleValue
|
||||
|
||||
def test_config_system():
|
||||
"""Test manuel du système de configuration."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== Test du Système de Configuration ===\n")
|
||||
|
||||
# 1. Test récupération des valeurs d'échelle
|
||||
print("1. Récupération des valeurs d'échelle:")
|
||||
scale_values = config_manager.get_competence_scale_values()
|
||||
for value, config in scale_values.items():
|
||||
print(f" {value}: {config['label']} (couleur: {config['color']}, inclus: {config['included_in_total']})")
|
||||
print()
|
||||
|
||||
# 2. Test modification d'une valeur
|
||||
print("2. Test modification de la valeur '2':")
|
||||
print(f" Avant: {scale_values['2']['label']}")
|
||||
|
||||
success = config_manager.update_scale_value('2', 'Acquis (modifié)', '#00ff00', True)
|
||||
print(f" Modification réussie: {success}")
|
||||
|
||||
updated_values = config_manager.get_competence_scale_values()
|
||||
print(f" Après: {updated_values['2']['label']}")
|
||||
print()
|
||||
|
||||
# 3. Test ajout d'une nouvelle valeur
|
||||
print("3. Test ajout d'une nouvelle valeur 'X':")
|
||||
success = config_manager.add_scale_value('X', 'Test Value', '#purple', False)
|
||||
print(f" Ajout réussi: {success}")
|
||||
|
||||
updated_values = config_manager.get_competence_scale_values()
|
||||
if 'X' in updated_values:
|
||||
print(f" Nouvelle valeur: X = {updated_values['X']['label']}")
|
||||
print()
|
||||
|
||||
# 4. Test validation
|
||||
print("4. Test validation des valeurs:")
|
||||
test_values = [
|
||||
('0', 'score'),
|
||||
('3', 'score'),
|
||||
('4', 'score'), # Invalid
|
||||
('15.5', 'notes'),
|
||||
('.', 'notes'),
|
||||
('X', 'score'), # Notre nouvelle valeur
|
||||
]
|
||||
|
||||
for value, grading_type in test_values:
|
||||
valid = config_manager.validate_grade_value(value, grading_type)
|
||||
print(f" {value} ({grading_type}): {'✓ Valide' if valid else '✗ Invalide'}")
|
||||
print()
|
||||
|
||||
# 5. Test informations d'affichage
|
||||
print("5. Test informations d'affichage:")
|
||||
display_tests = [
|
||||
('2', 'score'),
|
||||
('.', 'notes'),
|
||||
('15.5', 'notes'),
|
||||
('X', 'score'),
|
||||
]
|
||||
|
||||
for value, grading_type in display_tests:
|
||||
info = config_manager.get_display_info(value, grading_type)
|
||||
print(f" {value}: {info['label']} (couleur: {info['color']})")
|
||||
print()
|
||||
|
||||
# 6. Test suppression
|
||||
print("6. Test suppression de la valeur 'X':")
|
||||
success = config_manager.delete_scale_value('X')
|
||||
print(f" Suppression réussie: {success}")
|
||||
|
||||
final_values = config_manager.get_competence_scale_values()
|
||||
print(f" 'X' encore présente: {'X' in final_values}")
|
||||
print()
|
||||
|
||||
# 7. Vérification cohérence avec la base de données
|
||||
print("7. Vérification cohérence base de données:")
|
||||
db_values = CompetenceScaleValue.query.all()
|
||||
print(f" Nombre de valeurs en base: {len(db_values)}")
|
||||
print(f" Nombre de valeurs via config_manager: {len(final_values)}")
|
||||
print()
|
||||
|
||||
print("=== Test terminé avec succès ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_config_system()
|
||||
@@ -1,190 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test final complet pour valider que tout le système de valeurs spéciales
|
||||
fonctionne correctement et est entièrement flexible.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
from models import db, Grade
|
||||
import re
|
||||
|
||||
def test_final_complete():
|
||||
"""Test final complet du système flexible."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== TEST FINAL COMPLET : Système flexible des valeurs spéciales ===\n")
|
||||
|
||||
# 1. Configuration de base
|
||||
print("1. État de la configuration:")
|
||||
scale_values = config_manager.get_competence_scale_values()
|
||||
special_values = [v for v in scale_values.keys() if v not in ['0', '1', '2', '3']]
|
||||
|
||||
print(f" Valeurs spéciales configurées: {special_values}")
|
||||
for value in special_values:
|
||||
config = scale_values[value]
|
||||
print(f" '{value}': {config['label']} (couleur: {config['color']})")
|
||||
print()
|
||||
|
||||
# 2. Test de flexibilité - ajouter une nouvelle valeur spéciale
|
||||
print("2. Test de flexibilité - Ajout d'une nouvelle valeur 'x':")
|
||||
success = config_manager.add_scale_value('x', 'Excusé', '#9ca3af', False)
|
||||
print(f" Ajout de 'x' (Excusé): {success}")
|
||||
|
||||
if success:
|
||||
# Vérifier que la nouvelle valeur est prise en compte
|
||||
updated_values = config_manager.get_competence_scale_values()
|
||||
if 'x' in updated_values:
|
||||
print(f" ✅ Nouvelle valeur 'x': {updated_values['x']['label']}")
|
||||
else:
|
||||
print(" ❌ Nouvelle valeur 'x' non trouvée")
|
||||
print()
|
||||
|
||||
# 3. Test de l'interface avec la nouvelle valeur
|
||||
print("3. Test de l'interface avec la nouvelle valeur:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Vérifier les champs INPUT
|
||||
if 'type="text"' in content:
|
||||
print(" ✅ Champs INPUT de type 'text' (permettent valeurs spéciales)")
|
||||
else:
|
||||
print(" ❌ Champs INPUT toujours de type 'number'")
|
||||
|
||||
# Vérifier le placeholder
|
||||
placeholder_match = re.search(r'placeholder="([^"]*)"', content)
|
||||
if placeholder_match:
|
||||
placeholder = placeholder_match.group(1)
|
||||
if 'x' in placeholder:
|
||||
print(f" ✅ Placeholder inclut nouvelle valeur 'x': '{placeholder}'")
|
||||
else:
|
||||
print(f" 📋 Placeholder: '{placeholder}' (peut ne pas encore inclure 'x')")
|
||||
|
||||
# Vérifier la config JavaScript
|
||||
js_start = content.find('special_values: {')
|
||||
if js_start != -1:
|
||||
js_end = js_start + 500
|
||||
js_config = content[js_start:js_end]
|
||||
|
||||
if "'x'" in js_config:
|
||||
print(" ✅ Nouvelle valeur 'x' présente dans la config JavaScript")
|
||||
else:
|
||||
print(" 📋 Nouvelle valeur 'x' peut ne pas être encore dans le JS (cache possible)")
|
||||
|
||||
# Vérifier les options SELECT
|
||||
if 'value="x"' in content:
|
||||
print(" ✅ Nouvelle valeur 'x' présente dans les options SELECT")
|
||||
else:
|
||||
print(" 📋 Nouvelle valeur 'x' peut ne pas être encore dans les SELECT")
|
||||
print()
|
||||
|
||||
# 4. Test de saisie avec toutes les valeurs
|
||||
print("4. Test de saisie avec toutes les valeurs:")
|
||||
|
||||
# Nettoyer les données existantes
|
||||
Grade.query.filter_by(student_id=1).delete()
|
||||
db.session.commit()
|
||||
|
||||
# Test avec toutes les valeurs spéciales existantes + nouvelles
|
||||
all_special_values = [v for v in config_manager.get_competence_scale_values().keys()
|
||||
if v not in ['0', '1', '2', '3']]
|
||||
|
||||
with app.test_client() as client:
|
||||
test_data = {}
|
||||
for i, value in enumerate(all_special_values[:3], 1): # Tester les 3 premières
|
||||
test_data[f'grade_1_{i}'] = value
|
||||
|
||||
print(f" Données de test: {test_data}")
|
||||
|
||||
response = client.post('/assessments/1/grading/save',
|
||||
data=test_data,
|
||||
follow_redirects=False)
|
||||
|
||||
print(f" Soumission: statut {response.status_code}")
|
||||
|
||||
if response.status_code == 302:
|
||||
print(" ✅ Toutes les valeurs spéciales acceptées par le serveur")
|
||||
|
||||
# Vérifier les valeurs sauvées
|
||||
grades = Grade.query.filter_by(student_id=1).all()
|
||||
for grade in grades:
|
||||
display_info = config_manager.get_display_info(grade.value, 'score')
|
||||
print(f" Sauvé: '{grade.value}' → {display_info['label']}")
|
||||
else:
|
||||
print(" ❌ Erreur lors de la soumission")
|
||||
print()
|
||||
|
||||
# 5. Test des raccourcis clavier dynamiques
|
||||
print("5. Test des raccourcis clavier dynamiques:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Vérifier que le JavaScript utilise la liste dynamique
|
||||
if 'SPECIAL_VALUES_KEYS.includes(e.key)' in content:
|
||||
print(" ✅ JavaScript utilise la liste dynamique SPECIAL_VALUES_KEYS")
|
||||
else:
|
||||
print(" ❌ JavaScript utilise encore une liste hard-codée")
|
||||
|
||||
# Vérifier la définition de SPECIAL_VALUES_KEYS
|
||||
if 'const SPECIAL_VALUES_KEYS = Object.keys(GRADING_CONFIG.special_values);' in content:
|
||||
print(" ✅ SPECIAL_VALUES_KEYS défini dynamiquement")
|
||||
else:
|
||||
print(" ❌ SPECIAL_VALUES_KEYS non trouvé")
|
||||
print()
|
||||
|
||||
# 6. Test de validation
|
||||
print("6. Test de validation:")
|
||||
test_cases = [
|
||||
('.', 'notes', True, 'Valeur spéciale existante'),
|
||||
('d', 'notes', True, 'Valeur spéciale existante'),
|
||||
('x', 'notes', True, 'Nouvelle valeur spéciale'),
|
||||
('15.5', 'notes', True, 'Valeur numérique valide'),
|
||||
('abc', 'notes', False, 'Valeur invalide'),
|
||||
('-5', 'notes', False, 'Valeur négative'),
|
||||
]
|
||||
|
||||
for value, grade_type, expected, description in test_cases:
|
||||
is_valid = config_manager.validate_grade_value(value, grade_type)
|
||||
status = "✅" if is_valid == expected else "❌"
|
||||
print(f" {status} {description}: '{value}' → {is_valid} (attendu: {expected})")
|
||||
print()
|
||||
|
||||
# 7. Nettoyage - Supprimer la valeur de test
|
||||
print("7. Nettoyage:")
|
||||
if 'x' in config_manager.get_competence_scale_values():
|
||||
success = config_manager.delete_scale_value('x')
|
||||
print(f" Suppression de la valeur de test 'x': {success}")
|
||||
print()
|
||||
|
||||
# 8. Résumé final
|
||||
print("8. RÉSUMÉ FINAL - SYSTÈME FLEXIBLE :")
|
||||
|
||||
features = [
|
||||
"✅ Champs INPUT de type 'text' permettent la saisie libre",
|
||||
"✅ JavaScript entièrement dynamique (plus de hard-coding)",
|
||||
"✅ Placeholder généré automatiquement selon la configuration",
|
||||
"✅ Validation côté client et serveur",
|
||||
"✅ Configuration centralisée et flexible",
|
||||
"✅ Interface de configuration web fonctionnelle",
|
||||
"✅ Ajout/suppression de valeurs spéciales en temps réel",
|
||||
"✅ Raccourcis clavier s'adaptent automatiquement",
|
||||
]
|
||||
|
||||
for feature in features:
|
||||
print(f" {feature}")
|
||||
|
||||
print("\n 🎉 SUCCÈS COMPLET : Le système est maintenant entièrement flexible !")
|
||||
print(" 📋 Fonctionnalités validées:")
|
||||
print(" - Saisie libre des valeurs spéciales dans tous les champs")
|
||||
print(" - Configuration dynamique sans redémarrage")
|
||||
print(" - Interface utilisateur qui s'adapte automatiquement")
|
||||
print(" - Validation robuste côté client et serveur")
|
||||
print(" - Aucune valeur hard-codée dans le code")
|
||||
|
||||
print("\n=== Fin du test complet ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_final_complete()
|
||||
@@ -1,151 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test pour vérifier que les champs INPUT notes permettent maintenant
|
||||
la saisie des valeurs spéciales et que le JavaScript est dynamique.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
import re
|
||||
|
||||
def test_input_notes_fixed():
|
||||
"""Test des corrections pour les champs INPUT notes."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== TEST : Corrections champs INPUT notes ===\n")
|
||||
|
||||
# 1. Vérifier que les champs sont maintenant de type 'text'
|
||||
print("1. Vérification du type des champs INPUT:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Chercher les champs input de type notes
|
||||
input_pattern = r'<input[^>]*data-type="notes"[^>]*>'
|
||||
inputs = re.findall(input_pattern, content)
|
||||
|
||||
print(f" Champs INPUT notes trouvés: {len(inputs)}")
|
||||
|
||||
for i, input_html in enumerate(inputs[:2], 1): # Examiner les 2 premiers
|
||||
if 'type="text"' in input_html:
|
||||
print(f" ✅ Champ {i}: type='text' (permet valeurs spéciales)")
|
||||
elif 'type="number"' in input_html:
|
||||
print(f" ❌ Champ {i}: type='number' (bloque valeurs spéciales)")
|
||||
else:
|
||||
print(f" ⚠️ Champ {i}: type non spécifié")
|
||||
|
||||
# Vérifier le placeholder
|
||||
placeholder_match = re.search(r'placeholder="([^"]*)"', input_html)
|
||||
if placeholder_match:
|
||||
placeholder = placeholder_match.group(1)
|
||||
print(f" Placeholder: '{placeholder}'")
|
||||
print()
|
||||
|
||||
# 2. Vérifier la configuration JavaScript dynamique
|
||||
print("2. Vérification du JavaScript dynamique:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Vérifier la présence de SPECIAL_VALUES_KEYS
|
||||
if 'const SPECIAL_VALUES_KEYS = Object.keys(GRADING_CONFIG.special_values);' in content:
|
||||
print(" ✅ Variable SPECIAL_VALUES_KEYS définie dynamiquement")
|
||||
else:
|
||||
print(" ❌ Variable SPECIAL_VALUES_KEYS manquante")
|
||||
|
||||
# Vérifier l'utilisation de SPECIAL_VALUES_KEYS
|
||||
if 'SPECIAL_VALUES_KEYS.includes(e.key)' in content:
|
||||
print(" ✅ Utilisation dynamique de SPECIAL_VALUES_KEYS dans handleGradeKeydown")
|
||||
else:
|
||||
print(" ❌ Code utilise encore la liste hard-codée")
|
||||
|
||||
# Vérifier la fonction de validation
|
||||
if 'function validateGradeValue(' in content:
|
||||
print(" ✅ Fonction de validation validateGradeValue présente")
|
||||
else:
|
||||
print(" ❌ Fonction de validation manquante")
|
||||
print()
|
||||
|
||||
# 3. Vérifier les valeurs spéciales configurées
|
||||
print("3. Valeurs spéciales actuellement configurées:")
|
||||
scale_values = config_manager.get_competence_scale_values()
|
||||
special_values = [v for v in scale_values.keys() if v in ['.', 'd', 'a']]
|
||||
|
||||
print(f" Valeurs spéciales configurées: {special_values}")
|
||||
for value in special_values:
|
||||
config = scale_values[value]
|
||||
print(f" '{value}': {config['label']} (couleur: {config['color']})")
|
||||
print()
|
||||
|
||||
# 4. Test de la configuration JavaScript générée
|
||||
print("4. Configuration JavaScript des valeurs spéciales:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Extraire la section special_values
|
||||
start = content.find('special_values: {')
|
||||
if start != -1:
|
||||
end = content.find('}', start) + 1
|
||||
js_config = content[start:end]
|
||||
print(f" {js_config}")
|
||||
|
||||
# Vérifier que toutes les valeurs configurées sont présentes
|
||||
all_present = True
|
||||
for value in special_values:
|
||||
if f"'{value}'" in js_config:
|
||||
print(f" ✅ '{value}' présent dans la config JS")
|
||||
else:
|
||||
print(f" ❌ '{value}' absent de la config JS")
|
||||
all_present = False
|
||||
|
||||
if all_present:
|
||||
print(" ✅ Toutes les valeurs spéciales sont dans la config JS")
|
||||
else:
|
||||
print(" ❌ Configuration JavaScript non trouvée")
|
||||
print()
|
||||
|
||||
# 5. Test de saisie simulée
|
||||
print("5. Test de saisie avec valeurs spéciales:")
|
||||
|
||||
# Test de validation côté serveur
|
||||
test_cases = [
|
||||
('.', 'notes', 'Valeur spéciale point'),
|
||||
('d', 'notes', 'Valeur spéciale dispensé'),
|
||||
('15.5', 'notes', 'Valeur numérique valide'),
|
||||
('abc', 'notes', 'Valeur invalide'),
|
||||
]
|
||||
|
||||
for value, grade_type, description in test_cases:
|
||||
is_valid = config_manager.validate_grade_value(value, grade_type)
|
||||
status = "✅" if is_valid else "❌"
|
||||
print(f" {status} {description}: '{value}' → {is_valid}")
|
||||
print()
|
||||
|
||||
# 6. Résumé des améliorations
|
||||
print("6. RÉSUMÉ DES AMÉLIORATIONS:")
|
||||
|
||||
improvements = [
|
||||
"Champs INPUT changés de type='number' à type='text'",
|
||||
"Placeholder dynamique basé sur les valeurs configurées",
|
||||
"JavaScript utilise maintenant SPECIAL_VALUES_KEYS dynamique",
|
||||
"Plus de valeurs hard-codées ['.', 'd', 'a']",
|
||||
"Fonction de validation validateGradeValue ajoutée",
|
||||
"Validation immédiate avec feedback visuel",
|
||||
]
|
||||
|
||||
for improvement in improvements:
|
||||
print(f" ✅ {improvement}")
|
||||
|
||||
print("\n 🎉 SUCCÈS : Les champs INPUT notes sont maintenant flexibles !")
|
||||
print(" 📋 L'utilisateur peut maintenant:")
|
||||
print(" - Taper directement les valeurs spéciales dans les champs notes")
|
||||
print(" - Bénéficier d'une validation immédiate avec feedback visuel")
|
||||
print(" - Utiliser les raccourcis clavier pour toutes les valeurs configurées")
|
||||
print(" - Le système s'adapte automatiquement aux nouvelles valeurs ajoutées")
|
||||
|
||||
print("\n=== Fin du test ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_input_notes_fixed()
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test pour vérifier que les modifications de configuration sont bien
|
||||
prises en compte dans l'interface de notation.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
from models import db, Assessment, Student, GradingElement
|
||||
|
||||
def test_interface_sync():
|
||||
"""Test que l'interface de notation utilise les bonnes valeurs."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== TEST : Synchronisation interface de notation ===\n")
|
||||
|
||||
# 1. Modifier une valeur d'échelle
|
||||
print("1. Modification d'un label dans la configuration:")
|
||||
success = config_manager.update_scale_value('2', 'SUPER ACQUIS', '#00ff00', True)
|
||||
print(f" Modification du label '2' → 'SUPER ACQUIS': {success}")
|
||||
|
||||
# 2. Vérifier que get_display_info retourne la bonne valeur
|
||||
display_info = config_manager.get_display_info('2', 'score')
|
||||
print(f" get_display_info('2', 'score'): {display_info}")
|
||||
|
||||
# 3. Simuler l'appel à la route de notation
|
||||
assessment = Assessment.query.first()
|
||||
if assessment:
|
||||
print(f"\n2. Test avec une évaluation réelle: {assessment.title}")
|
||||
|
||||
students = Student.query.filter_by(class_group_id=assessment.class_group_id).all()
|
||||
grading_elements = []
|
||||
for exercise in assessment.exercises:
|
||||
for element in exercise.grading_elements:
|
||||
grading_elements.append(element)
|
||||
|
||||
# Simuler ce que fait la route
|
||||
scale_values = config_manager.get_competence_scale_values()
|
||||
|
||||
print(f" Nombre d'étudiants: {len(students)}")
|
||||
print(f" Nombre d'éléments de notation: {len(grading_elements)}")
|
||||
print(f" scale_values['2']['label']: '{scale_values['2']['label']}'")
|
||||
|
||||
# 4. Vérifier les éléments de type 'score'
|
||||
score_elements = [e for e in grading_elements if e.grading_type == 'score']
|
||||
print(f" Éléments de type 'score': {len(score_elements)}")
|
||||
|
||||
for element in score_elements[:2]: # Tester les 2 premiers
|
||||
print(f" - {element.label} (type: {element.grading_type})")
|
||||
|
||||
# Simuler l'affichage des options
|
||||
for value in ['0', '1', '2', '3']:
|
||||
display_info = config_manager.get_display_info(value, 'score')
|
||||
print(f" Option {value}: '{display_info['label']}' (couleur: {display_info['color']})")
|
||||
|
||||
# 5. Test des valeurs spéciales
|
||||
print("\n3. Test des valeurs spéciales:")
|
||||
special_values = ['.', 'd', 'a']
|
||||
for value in special_values:
|
||||
if value in scale_values:
|
||||
display_info = config_manager.get_display_info(value, 'score')
|
||||
print(f" Valeur '{value}': '{display_info['label']}' (couleur: {display_info['color']})")
|
||||
|
||||
# 6. Test avec une requête HTTP simulée
|
||||
print("\n4. Test d'accès à la route de notation:")
|
||||
with app.test_client() as client:
|
||||
if assessment:
|
||||
response = client.get(f'/assessments/{assessment.id}/grading')
|
||||
print(f" Statut de la réponse: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Vérifier que le label modifié apparaît dans le HTML
|
||||
if 'SUPER ACQUIS' in content:
|
||||
print(" ✅ Label modifié 'SUPER ACQUIS' trouvé dans le HTML")
|
||||
else:
|
||||
print(" ❌ Label modifié 'SUPER ACQUIS' NOT FOUND dans le HTML")
|
||||
# Chercher ce qui apparaît à la place
|
||||
import re
|
||||
matches = re.findall(r'value="2"[^>]*>2 \(([^)]+)\)', content)
|
||||
if matches:
|
||||
print(f" 📋 Label actuel pour '2': '{matches[0]}'")
|
||||
else:
|
||||
print(f" ❌ Erreur d'accès à la route: {response.status_code}")
|
||||
|
||||
print("\n=== Fin du test ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_interface_sync()
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from app import create_app
|
||||
|
||||
app = create_app('development')
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Chercher la section special_values
|
||||
start = content.find('special_values: {')
|
||||
if start != -1:
|
||||
end = content.find('}', start) + 1
|
||||
config_section = content[start:end]
|
||||
print('Configuration JavaScript:')
|
||||
print(config_section)
|
||||
else:
|
||||
print('Section special_values non trouvée')
|
||||
@@ -1,146 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test diagnostic pour identifier pourquoi les modifications des labels
|
||||
ne sont pas prises en compte dans l'application.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
from models import db, CompetenceScaleValue, GradingElement, Grade
|
||||
import json
|
||||
|
||||
def diagnostic_label_sync():
|
||||
"""Test diagnostic pour les problèmes de synchronisation des labels."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== DIAGNOSTIC : Problème de synchronisation des labels ===\n")
|
||||
|
||||
# 1. État initial des valeurs d'échelle
|
||||
print("1. État initial des valeurs d'échelle:")
|
||||
initial_values = config_manager.get_competence_scale_values()
|
||||
for value, config in initial_values.items():
|
||||
print(f" {value}: '{config['label']}' (couleur: {config['color']})")
|
||||
print()
|
||||
|
||||
# 2. Tester une modification d'un label via config_manager
|
||||
print("2. Test modification du label '2' via config_manager:")
|
||||
old_label = initial_values['2']['label']
|
||||
print(f" Ancien label pour '2': '{old_label}'")
|
||||
|
||||
success = config_manager.update_scale_value('2', 'ACQUIS MODIFIÉ', '#ff0000', True)
|
||||
print(f" Modification réussie: {success}")
|
||||
|
||||
# Vérifier que la modification a été prise en compte
|
||||
updated_values = config_manager.get_competence_scale_values()
|
||||
new_label = updated_values['2']['label']
|
||||
print(f" Nouveau label pour '2': '{new_label}'")
|
||||
print()
|
||||
|
||||
# 3. Tester get_display_info après modification
|
||||
print("3. Test get_display_info après modification:")
|
||||
display_info = config_manager.get_display_info('2', 'score')
|
||||
print(f" get_display_info('2', 'score'): {display_info}")
|
||||
print()
|
||||
|
||||
# 4. Vérifier directement dans la base de données
|
||||
print("4. Vérification directe dans la base de données:")
|
||||
db_value = CompetenceScaleValue.query.get('2')
|
||||
if db_value:
|
||||
print(f" Base de données - label pour '2': '{db_value.label}'")
|
||||
print(f" Base de données - couleur pour '2': '{db_value.color}'")
|
||||
else:
|
||||
print(" ERREUR: Valeur '2' non trouvée en base de données")
|
||||
print()
|
||||
|
||||
# 5. Tester les valeurs utilisées dans des templates simulés
|
||||
print("5. Test des sources de données pour templates:")
|
||||
|
||||
# get_competence_scale_values (utilisé dans templates)
|
||||
template_values = config_manager.get_competence_scale_values()
|
||||
print(f" Template source (get_competence_scale_values): '{template_values['2']['label']}'")
|
||||
|
||||
# get_score_meanings (configuration statique)
|
||||
score_meanings = config_manager.get_score_meanings()
|
||||
print(f" Score meanings statique: '{score_meanings[2]['label']}'")
|
||||
print()
|
||||
|
||||
# 6. Test avec un élément de notation réel
|
||||
print("6. Test avec éléments de notation existants:")
|
||||
grading_elements = GradingElement.query.filter_by(grading_type='score').limit(3).all()
|
||||
for element in grading_elements:
|
||||
print(f" Élément: {element.label} (type: {element.grading_type})")
|
||||
|
||||
# Chercher des grades pour cet élément
|
||||
grades = Grade.query.filter_by(grading_element_id=element.id).limit(3).all()
|
||||
for grade in grades:
|
||||
if grade.value in ['0', '1', '2', '3']:
|
||||
display_info = config_manager.get_display_info(grade.value, element.grading_type)
|
||||
print(f" Grade {grade.value} → Display: '{display_info['label']}' (couleur: {display_info['color']})")
|
||||
print()
|
||||
|
||||
# 7. Test des différentes méthodes d'affichage
|
||||
print("7. Comparaison des différentes sources de labels:")
|
||||
test_value = '2'
|
||||
|
||||
# Source 1: get_competence_scale_values (DB)
|
||||
scale_values = config_manager.get_competence_scale_values()
|
||||
source1 = scale_values[test_value]['label'] if test_value in scale_values else "NOT FOUND"
|
||||
|
||||
# Source 2: get_display_info (DB via get_competence_scale_values)
|
||||
display_info = config_manager.get_display_info(test_value, 'score')
|
||||
source2 = display_info['label']
|
||||
|
||||
# Source 3: get_score_meanings (statique)
|
||||
score_meanings = config_manager.get_score_meanings()
|
||||
source3 = score_meanings[int(test_value)]['label'] if int(test_value) in score_meanings else "NOT FOUND"
|
||||
|
||||
print(f" get_competence_scale_values: '{source1}'")
|
||||
print(f" get_display_info: '{source2}'")
|
||||
print(f" get_score_meanings: '{source3}'")
|
||||
print()
|
||||
|
||||
# 8. Diagnostic de cohérence
|
||||
print("8. Diagnostic de cohérence:")
|
||||
inconsistencies = []
|
||||
|
||||
for i in range(4): # Tester 0, 1, 2, 3
|
||||
value_str = str(i)
|
||||
|
||||
if value_str in scale_values and i in score_meanings:
|
||||
db_label = scale_values[value_str]['label']
|
||||
static_label = score_meanings[i]['label']
|
||||
|
||||
if db_label != static_label:
|
||||
inconsistencies.append({
|
||||
'value': value_str,
|
||||
'db_label': db_label,
|
||||
'static_label': static_label
|
||||
})
|
||||
|
||||
if inconsistencies:
|
||||
print(" 🚨 INCOHÉRENCES DÉTECTÉES:")
|
||||
for inc in inconsistencies:
|
||||
print(f" Valeur {inc['value']}: DB='{inc['db_label']}' vs Static='{inc['static_label']}'")
|
||||
else:
|
||||
print(" ✅ Aucune incohérence détectée")
|
||||
print()
|
||||
|
||||
# 9. Recommandations
|
||||
print("9. Recommandations pour corriger le problème:")
|
||||
|
||||
if inconsistencies:
|
||||
print(" 📋 Actions recommandées:")
|
||||
print(" - Les templates utilisent probablement get_score_meanings au lieu de get_competence_scale_values")
|
||||
print(" - Vérifier tous les templates qui affichent des labels de scores")
|
||||
print(" - S'assurer que get_display_info utilise bien la base de données")
|
||||
print(" - Mettre à jour get_score_meanings pour utiliser les valeurs DB ou supprimer cette méthode")
|
||||
else:
|
||||
print(" ✅ Configuration cohérente")
|
||||
print(" - Vérifier si le cache du navigateur pose problème")
|
||||
print(" - Tester la page de notation en direct")
|
||||
|
||||
print("\n=== Fin du diagnostic ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
diagnostic_label_sync()
|
||||
@@ -1,202 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test approfondi pour comprendre pourquoi les valeurs spéciales
|
||||
ne fonctionnent pas dans l'interface utilisateur.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
from models import db, Assessment, Student, GradingElement, Grade
|
||||
import re
|
||||
|
||||
def test_special_values_ui():
|
||||
"""Test approfondi de l'interface utilisateur pour les valeurs spéciales."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== DIAGNOSTIC APPROFONDI : Valeurs spéciales UI ===\n")
|
||||
|
||||
# 1. Vérifier les valeurs spéciales dans scale_values
|
||||
print("1. Configuration des valeurs spéciales:")
|
||||
scale_values = config_manager.get_competence_scale_values()
|
||||
|
||||
for key, config in scale_values.items():
|
||||
if key in ['.', 'd']:
|
||||
print(f" '{key}': {config}")
|
||||
print()
|
||||
|
||||
# 2. Examiner le HTML généré pour les selects
|
||||
print("2. Analyse du HTML généré pour les champs select:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Extraire toutes les options des selects
|
||||
option_pattern = r'<option value="([^"]*)"[^>]*>([^<]*)</option>'
|
||||
options = re.findall(option_pattern, content)
|
||||
|
||||
print(" Options trouvées dans les selects:")
|
||||
special_found = False
|
||||
for value, text in options[:20]: # Afficher les 20 premières
|
||||
if value in ['.', 'd']:
|
||||
print(f" ✅ value=\"{value}\" → {text}")
|
||||
special_found = True
|
||||
elif value in ['0', '1', '2', '3']:
|
||||
print(f" 📋 value=\"{value}\" → {text}")
|
||||
|
||||
if not special_found:
|
||||
print(" ❌ Aucune valeur spéciale trouvée dans les options")
|
||||
print()
|
||||
|
||||
# 3. Tester l'interface avec des éléments de type 'notes' vs 'score'
|
||||
print("3. Test par type d'élément de notation:")
|
||||
|
||||
assessment = Assessment.query.first()
|
||||
if assessment:
|
||||
grading_elements = []
|
||||
for exercise in assessment.exercises:
|
||||
for element in exercise.grading_elements:
|
||||
grading_elements.append(element)
|
||||
|
||||
score_elements = [e for e in grading_elements if e.grading_type == 'score']
|
||||
notes_elements = [e for e in grading_elements if e.grading_type == 'notes']
|
||||
|
||||
print(f" Éléments 'score': {len(score_elements)}")
|
||||
print(f" Éléments 'notes': {len(notes_elements)}")
|
||||
|
||||
for element in score_elements[:2]:
|
||||
print(f" Score: {element.label} (type: {element.grading_type})")
|
||||
|
||||
for element in notes_elements[:2]:
|
||||
print(f" Notes: {element.label} (type: {element.grading_type})")
|
||||
print()
|
||||
|
||||
# 4. Vérifier le JavaScript - chercher les configurations
|
||||
print("4. Analyse du JavaScript dans le template:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Chercher la configuration JavaScript
|
||||
js_config_pattern = r'special_values:\s*\{([^}]+)\}'
|
||||
js_match = re.search(js_config_pattern, content, re.DOTALL)
|
||||
|
||||
if js_match:
|
||||
js_config = js_match.group(1)
|
||||
print(" Configuration JavaScript des valeurs spéciales:")
|
||||
print(f" {js_config.strip()}")
|
||||
|
||||
# Vérifier si . et d sont dans la config JS
|
||||
if "'.':" in js_config:
|
||||
print(" ✅ Valeur '.' trouvée dans la config JS")
|
||||
else:
|
||||
print(" ❌ Valeur '.' NON trouvée dans la config JS")
|
||||
|
||||
if "'d':" in js_config:
|
||||
print(" ✅ Valeur 'd' trouvée dans la config JS")
|
||||
else:
|
||||
print(" ❌ Valeur 'd' NON trouvée dans la config JS")
|
||||
else:
|
||||
print(" ❌ Configuration JavaScript des valeurs spéciales NON trouvée")
|
||||
print()
|
||||
|
||||
# 5. Tester la navigation clavier JavaScript
|
||||
print("5. Test de la logique JavaScript pour valeurs spéciales:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Chercher la fonction handleGradeKeydown
|
||||
keydown_pattern = r'function handleGradeKeydown.*?\{(.*?)\n\}'
|
||||
keydown_match = re.search(keydown_pattern, content, re.DOTALL)
|
||||
|
||||
if keydown_match:
|
||||
keydown_function = keydown_match.group(1)
|
||||
print(" Fonction handleGradeKeydown trouvée")
|
||||
|
||||
# Vérifier si les valeurs spéciales sont gérées
|
||||
if '[\'.\', \'d\', \'a\']' in keydown_function:
|
||||
print(" ✅ Gestion des valeurs spéciales dans handleGradeKeydown")
|
||||
else:
|
||||
print(" ❌ Pas de gestion des valeurs spéciales dans handleGradeKeydown")
|
||||
|
||||
# Extraire la partie relevant des valeurs spéciales
|
||||
special_handling = re.search(r'if \(\[.*?\]\.includes\(e\.key\)\).*?\}', keydown_function, re.DOTALL)
|
||||
if special_handling:
|
||||
print(f" Gestion des valeurs spéciales:")
|
||||
print(f" {special_handling.group(0)[:200]}...")
|
||||
else:
|
||||
print(" ❌ Fonction handleGradeKeydown NON trouvée")
|
||||
print()
|
||||
|
||||
# 6. Test de saisie manuelle simulée
|
||||
print("6. Test de saisie manuelle:")
|
||||
|
||||
# Simuler ce qui se passe quand on tape '.' ou 'd'
|
||||
test_cases = [
|
||||
('1', '1', '.'), # student_id, element_id, value
|
||||
('1', '2', 'd'),
|
||||
('1', '3', '2'), # valeur normale pour comparaison
|
||||
]
|
||||
|
||||
with app.test_client() as client:
|
||||
for student_id, element_id, value in test_cases:
|
||||
form_data = {f'grade_{student_id}_{element_id}': value}
|
||||
|
||||
response = client.post('/assessments/1/grading/save',
|
||||
data=form_data,
|
||||
follow_redirects=False)
|
||||
|
||||
print(f" Saisie '{value}': statut {response.status_code}")
|
||||
|
||||
# Vérifier si la valeur a été sauvée
|
||||
grade = Grade.query.filter_by(
|
||||
student_id=student_id,
|
||||
grading_element_id=element_id
|
||||
).first()
|
||||
|
||||
if grade:
|
||||
print(f" → Valeur en base: '{grade.value}'")
|
||||
else:
|
||||
print(" → Aucune valeur en base")
|
||||
print()
|
||||
|
||||
# 7. Diagnostic des problèmes potentiels
|
||||
print("7. DIAGNOSTIC FINAL:")
|
||||
|
||||
problems = []
|
||||
|
||||
# Vérifier si les valeurs spéciales ont bien les options dans les selects
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
if 'value="."' not in content:
|
||||
problems.append("Options select pour '.' manquantes")
|
||||
if 'value="d"' not in content:
|
||||
problems.append("Options select pour 'd' manquantes")
|
||||
|
||||
# Vérifier les champs input (type notes)
|
||||
if 'placeholder="0 ou . d a"' in content:
|
||||
print(" ✅ Placeholder indique que les valeurs spéciales sont supportées pour 'notes'")
|
||||
else:
|
||||
problems.append("Placeholder ne mentionne pas les valeurs spéciales")
|
||||
|
||||
if problems:
|
||||
print(" 🚨 PROBLÈMES IDENTIFIÉS:")
|
||||
for problem in problems:
|
||||
print(f" - {problem}")
|
||||
else:
|
||||
print(" ✅ Configuration semble correcte")
|
||||
print(" 📋 Le problème pourrait être dans l'interaction utilisateur")
|
||||
|
||||
print("\n=== Fin du diagnostic ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_special_values_ui()
|
||||
@@ -1,155 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test pour comprendre exactement comment l'utilisateur essaie
|
||||
de saisir les valeurs spéciales et pourquoi ça ne marche pas.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
import re
|
||||
|
||||
def test_ui_interaction():
|
||||
"""Test des interactions utilisateur pour valeurs spéciales."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== DIAGNOSTIC : Interaction utilisateur valeurs spéciales ===\n")
|
||||
|
||||
# 1. Vérifier exactement ce que voit l'utilisateur
|
||||
print("1. HTML exact généré pour un champ de type 'score':")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Extraire un exemple de select complet
|
||||
select_pattern = r'(<select[^>]*name="grade_\d+_\d+"[^>]*>.*?</select>)'
|
||||
select_match = re.search(select_pattern, content, re.DOTALL)
|
||||
|
||||
if select_match:
|
||||
select_html = select_match.group(1)
|
||||
print(" SELECT complet:")
|
||||
# Nettoyer l'affichage
|
||||
lines = select_html.split('\n')
|
||||
for line in lines[:15]: # Afficher les 15 premières lignes
|
||||
print(f" {line.strip()}")
|
||||
print(" ...")
|
||||
else:
|
||||
print(" ❌ Aucun select trouvé")
|
||||
print()
|
||||
|
||||
# 2. Vérifier exactement ce que voit l'utilisateur pour les champs 'notes'
|
||||
print("2. HTML exact généré pour un champ de type 'notes':")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Extraire un exemple d'input de type notes
|
||||
input_pattern = r'(<input[^>]*data-type="notes"[^>]*>)'
|
||||
input_match = re.search(input_pattern, content)
|
||||
|
||||
if input_match:
|
||||
input_html = input_match.group(1)
|
||||
print(" INPUT notes:")
|
||||
print(f" {input_html}")
|
||||
else:
|
||||
print(" ❌ Aucun input notes trouvé")
|
||||
print()
|
||||
|
||||
# 3. Analyser les comportements possibles
|
||||
print("3. Analyse des comportements possibles:")
|
||||
|
||||
print(" Pour les champs SELECT (type 'score'):")
|
||||
print(" - L'utilisateur doit SÉLECTIONNER l'option dans la liste déroulante")
|
||||
print(" - Taper '.' ou 'd' au clavier PEUT fonctionner avec le JavaScript")
|
||||
print(" - Mais il faut que l'option existe dans le select")
|
||||
|
||||
print(" Pour les champs INPUT (type 'notes'):")
|
||||
print(" - L'utilisateur peut TAPER directement '.' ou 'd'")
|
||||
print(" - Le placeholder indique que c'est supporté")
|
||||
print(" - Le JavaScript gère les touches spéciales")
|
||||
print()
|
||||
|
||||
# 4. Test spécifique de l'interaction clavier
|
||||
print("4. Test du JavaScript de gestion clavier:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Chercher la fonction handleGradeKeydown complète
|
||||
keydown_start = content.find('function handleGradeKeydown')
|
||||
if keydown_start != -1:
|
||||
# Trouver la fin de la fonction
|
||||
brace_count = 0
|
||||
func_start = content.find('{', keydown_start)
|
||||
i = func_start + 1
|
||||
|
||||
while i < len(content) and not (brace_count == 0 and content[i] == '}'):
|
||||
if content[i] == '{':
|
||||
brace_count += 1
|
||||
elif content[i] == '}':
|
||||
brace_count -= 1
|
||||
i += 1
|
||||
|
||||
if i < len(content):
|
||||
keydown_function = content[keydown_start:i+1]
|
||||
|
||||
# Extraire la partie des valeurs spéciales
|
||||
special_part = re.search(r'if \(\[.*?\]\.includes\(e\.key\)\).*?return;', keydown_function, re.DOTALL)
|
||||
if special_part:
|
||||
print(" Gestion JavaScript des valeurs spéciales:")
|
||||
special_code = special_part.group(0)
|
||||
lines = special_code.split('\n')
|
||||
for line in lines:
|
||||
print(f" {line.strip()}")
|
||||
else:
|
||||
print(" ❌ Pas de gestion des valeurs spéciales trouvée")
|
||||
else:
|
||||
print(" ❌ Fonction handleGradeKeydown non trouvée")
|
||||
print()
|
||||
|
||||
# 5. Identifier les problèmes potentiels
|
||||
print("5. PROBLÈMES POTENTIELS IDENTIFIÉS:")
|
||||
|
||||
problems = []
|
||||
solutions = []
|
||||
|
||||
# Vérifier si la configuration JavaScript est correcte
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Configuration JavaScript
|
||||
if "special_values: {" in content:
|
||||
js_config_start = content.find("special_values: {")
|
||||
js_config_end = content.find("}", js_config_start) + 1
|
||||
js_config = content[js_config_start:js_config_end]
|
||||
|
||||
if "'.':" not in js_config:
|
||||
problems.append("Valeur '.' manquante dans la config JavaScript")
|
||||
solutions.append("Corriger la génération du JavaScript pour inclure '.'")
|
||||
|
||||
if "'d':" not in js_config:
|
||||
problems.append("Valeur 'd' manquante dans la config JavaScript")
|
||||
solutions.append("Corriger la génération du JavaScript pour inclure 'd'")
|
||||
|
||||
print(f" Configuration JavaScript actuelle:")
|
||||
print(f" {js_config}")
|
||||
else:
|
||||
problems.append("Configuration JavaScript des valeurs spéciales manquante")
|
||||
|
||||
if problems:
|
||||
print("\n 🚨 PROBLÈMES:")
|
||||
for i, problem in enumerate(problems):
|
||||
print(f" {i+1}. {problem}")
|
||||
|
||||
print("\n 💡 SOLUTIONS:")
|
||||
for i, solution in enumerate(solutions):
|
||||
print(f" {i+1}. {solution}")
|
||||
else:
|
||||
print(" ✅ Aucun problème technique identifié")
|
||||
print(" 📋 Le problème est peut-être dans l'expérience utilisateur")
|
||||
|
||||
print("\n=== Fin du diagnostic ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_ui_interaction()
|
||||
@@ -1,95 +0,0 @@
|
||||
# Tests Unitaires
|
||||
|
||||
Ce dossier contient les tests unitaires pour l'application de gestion scolaire.
|
||||
|
||||
## Structure des tests
|
||||
|
||||
```
|
||||
tests/
|
||||
├── __init__.py
|
||||
├── conftest.py # Configuration globale des tests
|
||||
├── test_app.py # Tests de l'application Flask
|
||||
├── test_models.py # Tests des modèles SQLAlchemy
|
||||
├── test_forms.py # Tests des formulaires WTForms
|
||||
├── test_services.py # Tests des services métier
|
||||
├── test_routes_assessments.py # Tests des routes d'évaluations
|
||||
└── test_utils.py # Tests des utilitaires
|
||||
```
|
||||
|
||||
## Exécution des tests
|
||||
|
||||
### Avec uv (recommandé)
|
||||
|
||||
```bash
|
||||
# Installer les dépendances de test
|
||||
uv sync
|
||||
|
||||
# Exécuter tous les tests
|
||||
uv run pytest tests/ -v
|
||||
|
||||
# Exécuter avec couverture de code
|
||||
uv run pytest tests/ --cov=. --cov-report=html
|
||||
|
||||
# Exécuter des tests spécifiques
|
||||
uv run pytest tests/test_models.py -v
|
||||
uv run pytest tests/test_models.py::TestClassGroup -v
|
||||
```
|
||||
|
||||
### Avec le script personnalisé
|
||||
|
||||
```bash
|
||||
# Tous les tests
|
||||
uv run python run_tests.py
|
||||
|
||||
# Avec rapport de couverture
|
||||
uv run python run_tests.py --coverage
|
||||
|
||||
# Tests d'un fichier spécifique
|
||||
uv run python run_tests.py test_models.py
|
||||
|
||||
# Mode silencieux
|
||||
uv run python run_tests.py --quiet
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Les tests utilisent:
|
||||
- **pytest** comme framework de test
|
||||
- **pytest-flask** pour l'intégration Flask
|
||||
- **pytest-cov** pour la couverture de code
|
||||
- **SQLite en mémoire** pour les tests de base de données
|
||||
|
||||
## Couverture des tests
|
||||
|
||||
Les tests couvrent:
|
||||
- ✅ Modèles SQLAlchemy (création, validation, relations)
|
||||
- ✅ Configuration de l'application Flask
|
||||
- ✅ Services métier (AssessmentService)
|
||||
- ✅ Utilitaires (validation, gestion d'erreurs)
|
||||
- ✅ Formulaires WTForms (validation)
|
||||
- ✅ Routes principales (responses HTTP)
|
||||
|
||||
## Bonnes pratiques
|
||||
|
||||
1. **Isolation**: Chaque test utilise une base de données temporaire
|
||||
2. **Fixtures**: Configuration partagée dans `conftest.py`
|
||||
3. **Nommage**: Tests préfixés par `test_`
|
||||
4. **Organisation**: Tests groupés par classe selon la fonctionnalité
|
||||
5. **Assertions**: Vérifications claires et spécifiques
|
||||
|
||||
## Ajout de nouveaux tests
|
||||
|
||||
Pour ajouter de nouveaux tests:
|
||||
|
||||
1. Créer un fichier `test_<module>.py`
|
||||
2. Importer les fixtures nécessaires
|
||||
3. OU utiliser les fixtures existantes (`app`, `client`)
|
||||
4. Suivre la convention de nommage
|
||||
|
||||
Exemple:
|
||||
```python
|
||||
def test_my_function(app):
|
||||
with app.app_context():
|
||||
# Votre test ici
|
||||
assert True
|
||||
```
|
||||
Reference in New Issue
Block a user