ScoDoc-PE/tests/unit/test_pe.py

352 lines
12 KiB
Python

"""
Test calcul moyennes pour les poursuites d'études
"""
import numpy as np
import pytest
import app.pe.moys.pe_moy
from tests.unit import setup
from app import db
import pandas as pd
import app.pe.moys.pe_moy as pe_moy
import app.pe.moys.pe_rcstag as pe_rcstag
import app.pe.moys.pe_tabletags as pe_tabletags
import app.pe.moys.pe_moytag as pe_moytag
def egalite_df(df1, df2):
return ((df1 == df2) | (np.isnan(df1) & np.isnan(df2))).all()
# ******************************
# app.pe.moys.pe_moy
# ******************************
class Test_pe_moy:
infos = {
"aggregat": "S1",
"tag": "maths",
"intitule": "UE1.1",
"cohorte": "groupe",
}
def test_init(self):
"""Test de pe_moy.Moyenne.__init__"""
notes = pd.Series({1: 10.0, 2: 14.0, 3: np.nan, 4: 0.0})
moy = pe_moy.Moyenne(notes, Test_pe_moy.infos)
assert moy.etudids == [1, 2, 3, 4], "Etudids incorrect"
assert moy.inscrits_ids == [1, 2, 4], "Inscriptions incorrectes"
# Les notes
notes_attendues = pd.Series([10.0, 14.0, np.nan, 0.0], index=[1, 2, 3, 4])
assert "note" in moy.df.columns, "Colonne manquante"
assert egalite_df(moy.df["note"], notes_attendues), "Notes incorrecte"
# Les étuds
nb_etuds = pd.Series([4] * 4, index=[1, 2, 3, 4])
assert "nb_etuds" in moy.df.columns, "Colonne manquante"
assert egalite_df(moy.df["nb_etuds"], nb_etuds)
# Les inscrits
nb_inscrits = pd.Series([3, 3, np.nan, 3], index=[1, 2, 3, 4])
assert "nb_inscrits" in moy.df.columns, "Colonne manquante"
assert egalite_df(moy.df["nb_inscrits"], nb_inscrits)
# Les classements
classement = pd.Series([2.0, 1.0, np.nan, 3.0], index=[1, 2, 3, 4])
assert "classement" in moy.df, "Colonne manquante"
assert egalite_df(moy.df["classement"], classement), "Classements incorrects"
# Les rangs
rang = pd.Series(["2/3", "1/3", "nan", "3/3"], index=[1, 2, 3, 4])
assert "rang" in moy.df, "Colonne manquante"
assert moy.df["rang"].isnull().sum() == 0, "Des Nan dans les rangs interdits"
assert (moy.df["rang"] == rang).any(), "Rangs incorrects"
# Les mins
assert "min" in moy.df, "Colonne manquante"
mina = pd.Series([0.0, 0.0, np.nan, 0.0], index=[1, 2, 3, 4])
assert egalite_df(moy.df["min"], mina), "Min incorrect"
# Les max
assert "max" in moy.df, "Colonne manquante"
maxa = pd.Series([14.0, 14.0, np.nan, 14.0], index=[1, 2, 3, 4])
assert egalite_df(moy.df["max"], maxa), "Max incorrect"
# Les moy
assert "moy" in moy.df, "Colonne manquante"
moya = pd.Series([8.0, 8.0, np.nan, 8.0], index=[1, 2, 3, 4])
assert egalite_df(moy.df["moy"], moya), "Moy incorrect"
def test_init_ex_aequo(self):
"""Test de pe_moy.Moyenne.__init__ pour des ex-aequo"""
notes = pd.Series({1: 10.0, 2: 14.0, 3: 10.0, 4: 0.0})
moy = pe_moy.Moyenne(notes, Test_pe_moy.infos)
# Les rangs
rang = pd.Series(["2 ex/4", "1/4", "2 ex/4", "3/4"], index=[1, 2, 3, 4])
assert moy.df["rang"].isnull().sum() == 0, "Des Nan dans les rangs interdits"
assert (moy.df["rang"] == rang).any(), "Rangs incorrects"
@pytest.mark.parametrize(
"notes, resultat",
[
pytest.param(
pd.Series({1: 10.0, 2: 14.0, 3: np.nan, 4: 0.0}), True, id="avec_notes"
),
pytest.param(pd.Series({1: np.nan, 2: np.nan}), False, id="sans_note"),
pytest.param(pd.Series({1: 0.0, 2: np.nan}), True, id="avec 0"),
],
)
def test_has_notes(self, notes, resultat):
moy = pe_moy.Moyenne(notes, Test_pe_moy.infos)
assert (
moy.has_notes() == resultat
), "Le test sur la présence de notes est incorrect"
@pytest.mark.parametrize(
"aggregat, tag, champ, cohorte, critere, attendu",
[
pytest.param(
"S1", "Math", "UE", "Gr", "note", "S1|Math|UE|Gr|note", id="tous_args"
),
pytest.param(
None,
"Math",
"UE",
"Gr",
"note",
"Math|UE|Gr|note",
id="aggregat manquant",
),
pytest.param(
None,
"Math",
"UE",
None,
"note",
"Math|UE|note",
id="aggregat et cohorte manquant",
),
],
)
def test_colonnes_df(self, aggregat, tag, champ, cohorte, critere, attendu):
descr = app.pe.moys.pe_moy.get_colonne_df(
aggregat, tag, champ, cohorte, critere
)
assert descr == attendu, "Nom de colonne incorrect"
def to_df(self):
notes = pd.Series({1: 10.0, 2: 14.0, 3: np.nan, 4: 0.0})
infos = {
"aggregat": "S1",
"tag": "maths",
"intitule": "Général",
"cohorte": "promo",
}
cols = [
f"S1|maths|Général|promo|{critere}"
for critere in ["note", "rang", "min", "max", "moy"]
]
moy = pe_moy.Moyenne(notes, infos)
df = moy.to_df(with_min_max_moy=True)
assert (
list(df.columns) == cols
), "Colonnes du df de synthèse pour Excel pas correctes"
# ******************************
# app.pe.moys.pe_moytag
# ******************************
class Test_pe_moytag:
infos = {"aggregat": "S1", "cohorte": "promo"}
def test_moyennes_tag__init__(self):
matrice_notes = pd.DataFrame.from_dict(
{
1: [12.0, 14.0, 15.0],
2: [8.0, np.nan, 12.0],
3: [0.0, 11.0, 13.0],
4: [np.nan, np.nan, np.nan],
5: [np.nan, np.nan, np.nan],
6: [0.0, 0.0, 0.0],
},
orient="index",
columns=["UE1.1", "UE1.2", "UE1.3"],
)
matrice_coeffs = pd.DataFrame.from_dict(
{
1: [1, 2, 3],
2: [2, 10, 6],
3: [1, 2, np.nan],
4: [5, 4, 3],
5: [np.nan, np.nan, np.nan],
6: [1, 1, 1],
},
orient="index",
columns=["UE1.1", "UE1.2", "UE1.3"],
)
moy_tag = pe_moytag.MoyennesTag(
"maths", None, matrice_notes, matrice_coeffs, Test_pe_moytag.infos
)
attendu = pd.Series(
[
(12 * 1 + 14 * 2 + 15 * 3) / (1 + 2 + 3),
(8 * 2 + 12 * 6) / (2 + 6),
(0 * 1 + 2 * 11) / (1 + 2),
np.nan,
np.nan,
0,
],
index=[1, 2, 3, 4, 5, 6],
)
assert egalite_df(moy_tag.notes_gen, attendu), "La moyenne n'est pas correcte"
def test_to_df_sans_renommage_colonne(self):
"""Test le dataframe de synthèse"""
infos = {"aggregat": "S1", "cohorte": "promo"}
matrice_notes = pd.DataFrame.from_dict(
{
2: [13.0, 13.0, 13],
1: [12.0, 14.0, 15.0],
},
orient="index",
columns=["UE1.1", "UE1.2", "UE1.3"],
)
matrice_coeffs = pd.DataFrame.from_dict(
{
2: [1, 2, 3],
1: [1, 2, 3],
},
orient="index",
columns=["UE1.1", "UE1.2", "UE1.3"],
)
moy_tag = pe_moytag.MoyennesTag(
"maths", None, matrice_notes, matrice_coeffs, infos
)
synthese = moy_tag.to_df(
aggregat="S1", cohorte="promo", options={"min_max_moy": True}
)
colonnes_attendues = []
for ue in ["UE1.1", "UE1.2", "UE1.3", "Général"]:
for champ in ["note", "rang", "min", "max", "moy"]:
colonnes_attendues += [f"S1|maths|{ue}|promo|{champ}"]
assert (
list(synthese.columns) == colonnes_attendues
), "Les colonnes de synthèse ne sont pas correctes"
assert list(synthese.index) == [
1,
2,
], "Les lignes ne sont pas triées par id d'étudiants"
@pytest.mark.parametrize(
"colonnes, ajouts, resultat",
[
pytest.param(["toto", "titi"], ["tutu"], None, id="pas de modif"),
pytest.param(["toto", "titi"], ["titi"], ["titi (1)"], id="ajout de (1)"),
pytest.param(
["toto", "toto (1)"], ["toto"], ["toto (2)"], id="ajout de (2)"
),
pytest.param(
["toto (1)", "titi (3)"],
["toto", "titi"],
["toto (4)", "titi (4)"],
id="ajout multiple",
),
],
)
def test_renomme_colonnes(self, colonnes, ajouts, resultat):
res = pe_moytag.ajout_numero_a_colonnes(colonnes, ajouts)
assert res == resultat, "L'ajout d'un numéro au colonne est incorrect"
# ******************************
# app.pe.moys.pe_rcstag
# ******************************
@pytest.mark.parametrize(
"notes_S1, notes_S2, coeffs_S1, coeffs_S2, "
"coeffs_rcues_S1, coeffs_rcues_S2, inscr_S1, inscr_S2,"
"moyenne, coeffs_aggreges",
[
pytest.param(
[17.0, 15.0, 12.0],
[16.0, 14.0, 13.0], # notes
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0], # coeffs moy gen
[2.0, 4.0, 6.0],
[8.0, 10.0, 12.0], # coeffs recus
[1.0, 1.0, 1.0],
[1.0, 1.0, 1.0], # inscr
[
(17.0 * 2.0 + 16.0 * 8.0) / (2.0 + 8.0),
(15.0 * 4.0 + 14.0 * 10.0) / (4.0 + 10.0),
(12.0 * 6.0 + 13.0 * 12.0) / (6.0 + 12.0),
],
[1.0 + 4.0, 2.0 + 5.0, 3.0 + 6.0],
id="etudiant_parfait",
),
pytest.param(
[17.0, 15.0, 12.0],
[16.0, 14.0, 13.0], # notes
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0], # coeffs moy gen
[2.0, 4.0, 6.0],
[8.0, 10.0, 12.0], # coeffs recus
[np.nan, 1.0, np.nan],
[1.0, np.nan, np.nan], # inscr
[
(16.0 * 8.0) / (8.0),
(15.0 * 4.0) / (4.0),
np.nan,
],
[4.0, 2.0, np.nan],
id="etudiant_non_inscrit",
),
pytest.param(
[0.0, 15.0, 0.0],
[0.0, 0.0, 0.0], # notes
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0], # coeffs moy gen
[2.0, 4.0, 6.0],
[8.0, 10.0, 12.0], # coeffs recus
[np.nan, 1.0, 1.0],
[1.0, np.nan, 1.0], # inscr
[0.0, 15.0, 0.0],
[4.0, 2.0, 3.0 + 6.0],
id="etudiant_avec_0",
),
],
)
def test_compute_moyennes_par_RCS(
notes_S1,
notes_S2,
coeffs_S1,
coeffs_S2,
coeffs_rcues_S1,
coeffs_rcues_S2,
inscr_S1,
inscr_S2,
moyenne,
coeffs_aggreges,
):
"""Test de pe_rcstag.compute_moyennes_par_RCS"""
notes_cube = np.stack([np.array([notes_S1]), np.array([notes_S2])], axis=-1)
# Vérifie les dimensions
dim1, dim2, dim3 = notes_cube.shape
assert dim1 == 1, "La dim 0 doit être le nombre d'étudiants"
assert dim2 == 3, "La dim 1 doit être le nombre d'UEs/Compétences"
assert dim3 == 2, "La dim 2 doit être le nombre de semestres"
coeffs_cube = np.stack([np.array([coeffs_S1]), np.array([coeffs_S2])], axis=-1)
coeffs_rcue_cube = np.stack(
[np.array([coeffs_rcues_S1]), np.array([coeffs_rcues_S2])], axis=-1
)
inscr_cube = np.stack([np.array([inscr_S1]), np.array([inscr_S2])], axis=-1)
moys, coeffs = pe_rcstag.compute_moyennes_par_RCS(
notes_cube, coeffs_cube, coeffs_rcue_cube, inscr_cube
)
moy_resultat = np.array([moyenne])
assert (
(moys == moy_resultat) | (np.isnan(moys) & np.isnan(moy_resultat))
).all(), "Moyenne erronée"
coeffs_resultat = np.array([coeffs_aggreges])
assert (
(coeffs == coeffs_resultat) | (np.isnan(coeffs) & np.isnan(coeffs_resultat))
).all(), "Coeffs (pour moyenne générale sur toutes les UE) erronés"