OC_P5 / tests /test_functional.py
KLEB38's picture
feat/setup SQL database and GET predict
61ff9dd
from fastapi.testclient import TestClient
from app.main import app
import logging
client = TestClient(app)
def test_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message":"Welcome to the FUTURISYS HR predictor API"}
def test_predict_valid():
payload = {
"Genre": "M",
"Statut Marital": "Marié(e)",
"Département": "Consulting",
"Poste": "Consultant",
"Domaine d'étude": "Infra & Cloud",
"Fréquence de déplacement": "Occasionnel",
"Heures supplémentaires": "Non",
"Âge": 32,
"Revenu mensuel": 4883,
"Nombre d'expériences précédentes": 1,
"Années d'expérience totale": 10,
"Années dans l'entreprise": 10,
"Années dans le poste actuel": 4,
"Nombre de formations suivies": 3,
"Distance domicile-travail": 7,
"Niveau d'éducation": 2,
"Années depuis la dernière promotion": 1,
"Années sous responsable actuel": 1,
"Satisfaction environnement": 4,
"Note évaluation précédente": 3,
"Satisfaction nature du travail": 3,
"Satisfaction équipe": 1,
"Satisfaction équilibre pro/perso": 3,
"Note évaluation actuelle": 3,
"Augmentation salaire précédente": "18%"
}
response = client.post("/predict", json=payload)
data = response.json()
assert response.status_code == 200
assert data["statut_employe"] == "The staff has a LOW probability of resigning"
assert data["probability_score"] == 0.28
assert data["model_threshold"] == 0.37
# Top 5 SHAP factors
factors = data["top_5_factors"]
assert list(factors.keys()) == [
"revenu_mensuel",
"annees_dans_l_entreprise",
"statut_marital_Célibataire",
"distance_domicile_travail",
"overall_satisfaction"
]
# Interpretations
assert factors["revenu_mensuel"]["interpretation"] == "Primary driver — decreases resignation risk"
assert factors["annees_dans_l_entreprise"]["interpretation"] == "Strong factor — decreases resignation risk"
assert factors["statut_marital_Célibataire"]["interpretation"] == "Moderate factor — decreases resignation risk"
assert factors["distance_domicile_travail"]["interpretation"] == "Contributing factor — decreases resignation risk"
assert factors["overall_satisfaction"]["interpretation"] == "Notable factor — decreases resignation risk"
# Feature values
assert factors["revenu_mensuel"]["feature_value"] == 4883.0
assert factors["annees_dans_l_entreprise"]["feature_value"] == 10.0
assert factors["statut_marital_Célibataire"]["feature_value"] == "encoded"
assert factors["distance_domicile_travail"]["feature_value"] == 7.0
assert factors["overall_satisfaction"]["feature_value"] == 2.75
class Test_Predict_422:
def test_predict_422_wrong_input(self):
payload = {
"Genre": "X", # INSERTION OF WRONG INPUT F OR M
"Statut Marital": "Marié(e)",
"Département": "Consulting",
"Poste": "Consultant",
"Domaine d'étude": "Infra & Cloud",
"Fréquence de déplacement": "Occasionnel",
"Heures supplémentaires": "Non",
"Âge": 32,
"Revenu mensuel": 4883,
"Nombre d'expériences précédentes": 1,
"Années d'expérience totale": 10,
"Années dans l'entreprise": 10,
"Années dans le poste actuel": 4,
"Nombre de formations suivies": 3,
"Distance domicile-travail": 7,
"Niveau d'éducation": 2,
"Années depuis la dernière promotion": 1,
"Années sous responsable actuel": 1,
"Satisfaction environnement": 4,
"Note évaluation précédente": 3,
"Satisfaction nature du travail": 3,
"Satisfaction équipe": 1,
"Satisfaction équilibre pro/perso": 3,
"Note évaluation actuelle": 3,
"Augmentation salaire précédente": "18%"
}
response = client.post("/predict", json=payload)
assert response.status_code == 422
def test_predict_422_wrong_type_str(self):
payload = {
"Genre": "M",
"Statut Marital": "Marié(e)",
"Département": "Consulting",
"Poste": "Consultant",
"Domaine d'étude": "Infra & Cloud",
"Fréquence de déplacement": "Occasionnel",
"Heures supplémentaires": "Non",
"Âge": "trente", #EXPECTED INT
"Revenu mensuel": 4883,
"Nombre d'expériences précédentes": 1,
"Années d'expérience totale": 10,
"Années dans l'entreprise": 10,
"Années dans le poste actuel": 4,
"Nombre de formations suivies": 3,
"Distance domicile-travail": 7,
"Niveau d'éducation": 2,
"Années depuis la dernière promotion": 1,
"Années sous responsable actuel": 1,
"Satisfaction environnement": 4,
"Note évaluation précédente": 3,
"Satisfaction nature du travail": 3,
"Satisfaction équipe": 1,
"Satisfaction équilibre pro/perso": 3,
"Note évaluation actuelle": 3,
"Augmentation salaire précédente": "18%"
}
response = client.post("/predict", json=payload)
assert response.status_code == 422
def test_predict_422_wrong_type_int(self):
payload = {
"Genre": "M",
"Statut Marital": "Marié(e)",
"Département": "Consulting",
"Poste": "Consultant",
"Domaine d'étude": "Infra & Cloud",
"Fréquence de déplacement": "Occasionnel",
"Heures supplémentaires": "Non",
"Âge": 32,
"Revenu mensuel": 4883.12,#WRONG TYPE, should be int
"Nombre d'expériences précédentes": 1,
"Années d'expérience totale": 10,
"Années dans l'entreprise": 10,
"Années dans le poste actuel": 4,
"Nombre de formations suivies": 3,
"Distance domicile-travail": 7,
"Niveau d'éducation": 2,
"Années depuis la dernière promotion": 1,
"Années sous responsable actuel": 1,
"Satisfaction environnement": 4,
"Note évaluation précédente": 3,
"Satisfaction nature du travail": 3,
"Satisfaction équipe": 1,
"Satisfaction équilibre pro/perso": 3,
"Note évaluation actuelle": 3,
"Augmentation salaire précédente": "18%"
}
response = client.post("/predict", json=payload)
assert response.status_code == 422
def test_predict_422_incomplete_json(self):
payload = {
"Genre": "M",
"Statut Marital": "Marié(e)",
"Département": "Consulting",
"Poste": "Consultant",
"Domaine d'étude": "Infra & Cloud",
"Fréquence de déplacement": "Occasionnel",
"Heures supplémentaires": "Non",
"Âge": 32,
"Revenu mensuel": 4883,
"Nombre d'expériences précédentes": 1,
"Années d'expérience totale": 10,
"Années dans l'entreprise": 10,
"Années dans le poste actuel": 4,
"Nombre de formations suivies": 3,
"Niveau d'éducation": 2, #MISSING "Distance domicile-travail"
"Années depuis la dernière promotion": 1,
"Années sous responsable actuel": 1,
"Satisfaction environnement": 4,
"Note évaluation précédente": 3,
"Satisfaction nature du travail": 3,
"Satisfaction équipe": 1,
"Satisfaction équilibre pro/perso": 3,
"Note évaluation actuelle": 3,
"Augmentation salaire précédente": "18%"
}
response = client.post("/predict", json=payload)
assert response.status_code == 422
def test_logging(caplog):
payload = {
"Genre": "M",
"Statut Marital": "Marié(e)",
"Département": "Logistique", #check wrong department
"Poste": "Consultant",
"Domaine d'étude": "Infra & Cloud",
"Fréquence de déplacement": "Occasionnel",
"Heures supplémentaires": "Non",
"Âge": 32,
"Revenu mensuel": 4883,
"Nombre d'expériences précédentes": 1,
"Années d'expérience totale": 10,
"Années dans l'entreprise": 10,
"Années dans le poste actuel": 4,
"Nombre de formations suivies": 3,
"Distance domicile-travail": 7,
"Niveau d'éducation": 2,
"Années depuis la dernière promotion": 1,
"Années sous responsable actuel": 1,
"Satisfaction environnement": 4,
"Note évaluation précédente": 3,
"Satisfaction nature du travail": 3,
"Satisfaction équipe": 1,
"Satisfaction équilibre pro/perso": 3,
"Note évaluation actuelle": 3,
"Augmentation salaire précédente": "18%"
}
with caplog.at_level(logging.WARNING):
response = client.post("/predict", json=payload)
assert response.status_code == 200 # l'API répond quand même
assert "Unknown value 'Logistique' for column 'departement'" in caplog.text
def test_predict_by_id_valid():
response = client.get("/predict/1")
data=response.json()
assert response.status_code==200
assert "statut_employe" in data
assert "probability_score" in data
assert "top_5_factors" in data
def test_predict_by_id_not_found():
response = client.get("/predict/99999")
assert response.status_code == 404
assert response.json()["detail"] == "Employee ID not found in database"