"""
Tests unitaires pour la route /api/plot-data de l'API IHM.
Ce module contient les tests pour vérifier le bon fonctionnement
de la route qui fournit les données pour les graphiques.
Les tests vérifient :
1. Le format de la réponse de l'API
2. La gestion des erreurs (fichier non trouvé)
3. La cohérence des données retournées
Version: 1.0.0 (2024-03-19)
Auteur: Kahina et franck - Groupe 2
"""
import unittest
import json
import os
import sys
from unittest.mock import patch, mock_open
import pandas as pd
import numpy as np
from flask import Flask
import logging
# Configuration du logging pour les tests
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Ajout du chemin src au PYTHONPATH pour trouver les modules à tester
current_dir = os.path.dirname(os.path.abspath(__file__))
src_path = os.path.join(current_dir, '..', 'src')
sys.path.insert(0, src_path)
logger.info(f"Ajout du chemin au PYTHONPATH: {src_path}")
# Import du module à tester
from main.routes import main_bp
[docs]
class TestPlotDataRoute(unittest.TestCase):
"""
Classe de test pour la route /api/plot-data.
Cette classe teste le comportement de l'endpoint qui fournit
les données pour les graphiques de l'interface.
Tests effectués:
- Format de la réponse API
- Gestion des erreurs
- Cohérence des données
"""
[docs]
def setUp(self):
"""
Configuration initiale pour chaque test.
Cette méthode est exécutée avant chaque test et configure:
- Une application Flask de test
- Un client de test
- Les données de test communes
"""
logger.info("Initialisation d'un nouveau test...")
# Configuration de l'application Flask de test
self.app = Flask(__name__)
self.app.register_blueprint(main_bp)
self.client = self.app.test_client()
self.app.config['TESTING'] = True
os.environ['PYTHON_ENV'] = 'test'
logger.debug("Application Flask de test configurée")
# Création des données de test communes
# Ces données simulent des mesures sur 3 jours avec des valeurs croissantes
self.test_data = pd.DataFrame({
'year': [2024] * 3, # Année constante
'month': [3] * 3, # Mois constant (mars)
'day': [1, 2, 3], # Trois jours consécutifs
'pm2.5': [10.0, 20.0, 30.0], # Valeurs PM2.5 croissantes
'TEMP': [20.0, 25.0, 30.0], # Température croissante
'DEWP': [15.0, 18.0, 21.0], # Point de rosée croissant
'PRES': [1013.0, 1014.0, 1015.0], # Pression croissante
'Iws': [2.0, 3.0, 4.0], # Vitesse du vent croissante
'Is': [8.0, 7.0, 6.0], # Ensoleillement décroissant
'Ir': [0.0, 0.5, 1.0] # Précipitations croissantes
})
logger.debug("Données de test générées")
[docs]
def test_plot_data_file_not_found(self):
"""
Test de la gestion d'erreur quand le fichier de données n'existe pas.
Vérifie:
- Le code d'erreur 404
- Le format du message d'erreur
- Le contenu du message d'erreur
"""
logger.info("Début du test de fichier non trouvé")
# Simulation de l'absence du fichier
with patch('os.path.exists', return_value=False):
logger.debug("Simulation de fichier manquant")
response = self.client.get('/api/plot-data')
# Vérification du code d'erreur
self.assertEqual(response.status_code, 404)
logger.debug("Code 404 reçu comme attendu")
# Vérification du message d'erreur
data = json.loads(response.data)
self.assertIn('error', data)
self.assertTrue(isinstance(data['error'], str))
self.assertIn('Fichier de données non trouvé', data['error'])
logger.debug(f"Message d'erreur vérifié: {data['error']}")
logger.info("Test de fichier non trouvé terminé avec succès")
[docs]
def test_plot_data_values_consistency(self):
"""
Test de la cohérence des données retournées.
Vérifie:
- Le format des dates
- La cohérence des valeurs PM2.5
- La structure des variables corrélées
- La normalisation des données
"""
logger.info("Début du test de cohérence des données")
with patch('pandas.read_csv', return_value=self.test_data), \
patch('os.path.exists', return_value=True):
response = self.client.get('/api/plot-data')
self.assertEqual(response.status_code, 200)
data = json.loads(response.data)
logger.debug("Données reçues de l'API")
# Test des dates
self.assertEqual(len(data['dates']), 3)
self.assertTrue(all(isinstance(d, str) for d in data['dates']))
logger.debug("Format des dates vérifié")
# Test des valeurs PM2.5
self.assertEqual(len(data['pm25']), 3)
self.assertTrue(
all(isinstance(v, (int, float)) for v in data['pm25']))
logger.debug("Types des valeurs PM2.5 vérifiés")
# Vérification de l'ordre croissant des PM2.5
self.assertTrue(
data['pm25'][0] < data['pm25'][1] < data['pm25'][2])
logger.debug("Ordre croissant des PM2.5 vérifié")
# Test des variables corrélées
self.assertTrue(len(data['correlated_vars']) >= 5)
for var in data['correlated_vars']:
self.assertIn('name', var)
self.assertIn('label', var)
logger.debug("Structure des variables corrélées vérifiée")
# Test des valeurs normalisées
for var in ['TEMP', 'DEWP', 'PRES', 'Iws', 'Is']:
if var in data:
values = np.array(data[var])
mean_val = abs(np.mean(values))
std_val = np.std(values)
# Vérification de la normalisation
self.assertLess(
mean_val, 0.5,
f"Moyenne de {var} ({mean_val:.2f}) devrait être proche de 0"
)
self.assertTrue(
0.5 <= std_val <= 1.5,
f"Écart-type de {var} ({std_val:.2f}) devrait être proche de 1"
)
logger.debug(
f"Variable {var} - moyenne: {mean_val:.2f}, écart-type: {std_val:.2f}"
)
logger.info("Test de cohérence des données terminé avec succès")
if __name__ == '__main__':
unittest.main()