""" test_app.py : tests de non-régression d'Avis'IA Resto Usage : python test_app.py Produit un rapport horodaté rapport_tests.txt Fonctionne avec ou sans clé API Mistral (le mode secours est testé aussi). """ import os from datetime import datetime import app RESULTATS = [] def verifier(nom, condition, detail=""): RESULTATS.append((nom, bool(condition), detail)) print(f"{'✅' if condition else '❌'} {nom}" + (f" ({detail})" if detail else "")) def main(): print("=" * 60) print("TESTS AVIS'IA RESTO,", datetime.now().strftime("%d/%m/%Y %H:%M")) print("=" * 60) mode_ia = app.client is not None # 1. Robustesse : avis vide r, m = app.generer_reponse("", 3, "Test", "Test") verifier("Avis vide refusé avec message clair", "⚠️" in m) # 2. Avis négatif : une réponse est toujours produite r_neg, m_neg = app.generer_reponse("Service très lent, plat froid, très déçu.", 1, "Le Normand Caen", "Marc, gérant") verifier("Avis négatif : réponse produite", len(r_neg) > 30) verifier("Mode affiché à l'utilisateur", ("✅" in m_neg) or ("🔶" in m_neg)) # 3. Avis positif r_pos, m_pos = app.generer_reponse("Excellente tarte normande, accueil parfait !", 5, "Le Normand Caen", "Marc, gérant") verifier("Avis positif : réponse produite", len(r_pos) > 30) # 4. Rubrique qualité : longueur, absence de promesses interdites, # personnalisation (uniquement significative en mode IA) ok_neg, detail_neg = app._controle_qualite( "Service très lent, plat froid, très déçu.", r_neg, verifier_personnalisation=("✅" in m_neg)) verifier("Qualité rubrique : avis négatif", ok_neg, detail_neg) ok_pos, detail_pos = app._controle_qualite( "Excellente tarte normande, accueil parfait !", r_pos, verifier_personnalisation=("✅" in m_pos)) verifier("Qualité rubrique : avis positif", ok_pos, detail_pos) verifier("Réponse négative différente de la réponse positive", r_neg.strip() != r_pos.strip()) # 5. Toutes les notes ont un template de secours verifier("Templates de secours pour les 5 notes", all(n in app.TEMPLATES for n in range(1, 6))) # 6. Analyse CSV multi-restaurants (onglet 2), séparateur virgule exemple = "avis_restaurant_exemple.csv" if os.path.exists(exemple): class F: name = exemple s, f1, f2, f3, f4, f5, f6, f7 = app.analyser_csv(F()) verifier("CSV multi-restaurants : analyse sans erreur", s.startswith("###")) figs_ok = all(hasattr(f, "size") and f.size[0] > 0 and f.size[1] > 0 for f in (f1, f2, f3, f4, f5, f6, f7)) verifier("Les 7 graphiques contiennent des données", figs_ok) fonds_ok = all(f.mode in ("RGB", "RGBA") for f in (f1, f2, f3, f4, f5, f6, f7)) verifier("Les 7 graphiques sont des images valides (RGB/RGBA)", fonds_ok) else: verifier("CSV multi-restaurants présent", False, "fichier introuvable") # 7. Analyse CSV, séparateur point-virgule if os.path.exists(exemple): import pandas as pd pd.read_csv(exemple).to_csv("_test_pv.csv", sep=";", index=False) class G: name = "_test_pv.csv" s2, *_ = app.analyser_csv(G()) verifier("Séparateur point-virgule détecté automatiquement", s2.startswith("###")) os.remove("_test_pv.csv") # 8. CSV d'analyse invalide (colonnes manquantes) with open("_test_ko.csv", "w", encoding="utf-8") as f: f.write("colonne_inconnue\nvaleur\n") class H: name = "_test_ko.csv" s3, *_ = app.analyser_csv(H()) verifier("CSV d'analyse invalide : message d'erreur explicite", s3.startswith("❌")) os.remove("_test_ko.csv") # 9. Traitement en lot (onglet 1, dépôt CSV) avec le CSV d'exemple lot = "avis_a_repondre_exemple.csv" if os.path.exists(lot): class I: name = lot statut_lot, apercu, chemin = app.generer_reponses_batch(I()) verifier("CSV en lot : traitement sans erreur", statut_lot.startswith("✅")) verifier("CSV en lot : une réponse par ligne", apercu is not None and len(apercu) > 0 and apercu["reponse_generee"].notna().all()) verifier("CSV en lot : fichier de sortie créé", chemin is not None and os.path.exists(chemin)) tableau_html = app._df_vers_tableau_html(apercu) verifier("Tableau HTML : vrai tableau sans coin arrondi", "