forked from ScoDoc/DocScoDoc
Tests YAML jury BUT: amélioration code test + yaml GEII Lyon ok
This commit is contained in:
parent
2241049280
commit
592d0741ea
@ -170,7 +170,7 @@ class DecisionsProposees:
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"""<{self.__class__.__name__} valid={self.code_valide
|
||||
} codes={self.codes} explanation={self.explanation}"""
|
||||
} codes={self.codes} explanation={self.explanation}>"""
|
||||
|
||||
|
||||
class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
@ -732,7 +732,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
if self.formsemestre_pair is not None:
|
||||
sco_cache.invalidate_formsemestre(formsemestre_id=self.formsemestre_pair.id)
|
||||
|
||||
def record_all(self):
|
||||
def record_all(self, no_overwrite: bool = True):
|
||||
"""Enregistre les codes qui n'ont pas été spécifiés par le formulaire,
|
||||
et sont donc en mode "automatique"
|
||||
"""
|
||||
@ -746,7 +746,8 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
# rappel: le code par défaut est en tête
|
||||
code = dec.codes[0] if dec.codes else None
|
||||
# enregistre le code jury seulement s'il n'y a pas déjà de code
|
||||
dec.record(code, no_overwrite=True)
|
||||
# (no_overwrite=True) sauf en mode test yaml
|
||||
dec.record(code, no_overwrite=no_overwrite)
|
||||
|
||||
def erase(self, only_one_sem=False):
|
||||
"""Efface les décisions de jury de cet étudiant
|
||||
@ -922,6 +923,10 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
||||
else:
|
||||
self.codes.insert(1, self.code_valide)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"""<{self.__class__.__name__} rcue={self.rcue} valid={self.code_valide
|
||||
} codes={self.codes} explanation={self.explanation}"""
|
||||
|
||||
def record(self, code: str, no_overwrite=False):
|
||||
"""Enregistre le code"""
|
||||
if self.rcue is None:
|
||||
@ -1073,7 +1078,7 @@ class DecisionsProposeesUE(DecisionsProposees):
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"""<{self.__class__.__name__} ue={self.ue.acronyme} valid={self.code_valide
|
||||
} codes={self.codes} explanation={self.explanation}"""
|
||||
} codes={self.codes} explanation={self.explanation}>"""
|
||||
|
||||
def set_rcue(self, rcue: RegroupementCoherentUE):
|
||||
"""Rattache cette UE à un RCUE. Cela peut modifier les codes
|
||||
|
@ -15,12 +15,17 @@ from app.scodoc import sco_cache
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def formsemestre_validation_auto_but(formsemestre: FormSemestre, only_adm=True) -> int:
|
||||
def formsemestre_validation_auto_but(
|
||||
formsemestre: FormSemestre, only_adm: bool = True, no_overwrite: bool = True
|
||||
) -> int:
|
||||
"""Calcul automatique des décisions de jury sur une année BUT.
|
||||
Normalement, only_adm est True et on n'enregistre que les décisions ADM (de droit).
|
||||
Si only_adm est faux, on enregistre la première décision proposée par ScoDoc
|
||||
(mode à n'utiliser que pour les tests)
|
||||
|
||||
Si no_overwrite est vrai (défaut), ne ré-écrit jamais les codes déjà enregistrés
|
||||
(utiliser faux pour certains tests)
|
||||
|
||||
Returns: nombre d'étudiants "admis"
|
||||
"""
|
||||
if not formsemestre.formation.is_apc():
|
||||
@ -33,7 +38,7 @@ def formsemestre_validation_auto_but(formsemestre: FormSemestre, only_adm=True)
|
||||
if deca.admis: # année réussie
|
||||
nb_admis += 1
|
||||
if deca.admis or not only_adm:
|
||||
deca.record_all()
|
||||
deca.record_all(no_overwrite=no_overwrite)
|
||||
|
||||
db.session.commit()
|
||||
return nb_admis
|
||||
|
@ -194,12 +194,11 @@ Etudiants:
|
||||
decision_jury: CMP
|
||||
rcue:
|
||||
moy_rcue: 10.75
|
||||
est_compensable: False
|
||||
est_compensable: True
|
||||
"UE12":
|
||||
code_valide: CMP
|
||||
decision_jury: CMP
|
||||
code_valide: CMP # car validé en fin de S2
|
||||
rcue:
|
||||
moy_rcue: 10.50
|
||||
moy_rcue: 9.50 # la moyenne courante (et non enregistrée), donc pas 10.5
|
||||
est_compensable: False
|
||||
decision_annee: ADM
|
||||
|
@ -35,7 +35,7 @@ def test_but_jury_GB(test_client):
|
||||
|
||||
# Vérifie les deca de tous les semestres:
|
||||
for formsemestre in FormSemestre.query:
|
||||
_check_deca(formsemestre)
|
||||
yaml_setup.check_deca_fields(formsemestre)
|
||||
|
||||
# Saisie de toutes les décisions de jury
|
||||
for formsemestre in FormSemestre.query.order_by(FormSemestre.semestre_id):
|
||||
@ -43,11 +43,11 @@ def test_but_jury_GB(test_client):
|
||||
|
||||
# Vérifie résultats attendus:
|
||||
S1: FormSemestre = FormSemestre.query.filter_by(titre="S1_SEE").first()
|
||||
_test_but_jury(S1, doc)
|
||||
yaml_setup.test_but_jury(S1, doc)
|
||||
S2: FormSemestre = FormSemestre.query.filter_by(titre="S2_SEE").first()
|
||||
_test_but_jury(S2, doc)
|
||||
yaml_setup.test_but_jury(S2, doc)
|
||||
S3: FormSemestre = FormSemestre.query.filter_by(titre="S3").first()
|
||||
_test_but_jury(S3, doc)
|
||||
yaml_setup.test_but_jury(S3, doc)
|
||||
# _test_but_jury(S1_redoublant, doc)
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ def test_but_jury_GMP_lm(test_client):
|
||||
|
||||
# Vérifie les deca de tous les semestres:
|
||||
for formsemestre in formsemestres:
|
||||
_check_deca(formsemestre)
|
||||
yaml_setup.check_deca_fields(formsemestre)
|
||||
|
||||
# Saisie de toutes les décisions de jury qui ne le seraient pas déjà
|
||||
for formsemestre in formsemestres:
|
||||
@ -74,7 +74,7 @@ def test_but_jury_GMP_lm(test_client):
|
||||
|
||||
# Vérifie résultats attendus:
|
||||
for formsemestre in formsemestres:
|
||||
_test_but_jury(formsemestre, doc)
|
||||
yaml_setup.test_but_jury(formsemestre, doc)
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
@ -90,71 +90,14 @@ def test_but_jury_GEII_lyon(test_client):
|
||||
FormSemestre.date_debut, FormSemestre.semestre_id
|
||||
).all()
|
||||
|
||||
# Vérifie les deca de tous les semestres:
|
||||
# Vérifie les champs de DecisionsProposeesAnnee de tous les semestres:
|
||||
for formsemestre in formsemestres:
|
||||
_check_deca(formsemestre)
|
||||
yaml_setup.check_deca_fields(formsemestre)
|
||||
|
||||
# Saisie de toutes les décisions de jury qui ne le seraient pas déjà
|
||||
# Saisie de toutes les décisions de jury "automatiques"
|
||||
# et vérification des résultats attendus:
|
||||
for formsemestre in formsemestres:
|
||||
formsemestre_validation_auto_but(formsemestre, only_adm=False)
|
||||
|
||||
# Vérifie résultats attendus:
|
||||
for formsemestre in formsemestres:
|
||||
_test_but_jury(formsemestre, doc)
|
||||
|
||||
|
||||
def _check_deca(formsemestre: FormSemestre, etud: Identite = None):
|
||||
"""vérifie les champs principaux de l'instance de DecisionsProposeesAnnee"""
|
||||
etud = etud or formsemestre.etuds.first()
|
||||
assert etud # il faut au moins un étudiant dans le semestre
|
||||
deca = DecisionsProposeesAnnee(etud, formsemestre)
|
||||
assert deca.validation is None # pas encore de validation enregistrée
|
||||
assert False is deca.recorded
|
||||
assert deca.code_valide is None
|
||||
if formsemestre.semestre_id % 2:
|
||||
assert deca.formsemestre_impair == formsemestre
|
||||
assert formsemestre.query_ues_parcours_etud(etud.id).all() == deca.ues_impair
|
||||
else:
|
||||
assert deca.formsemestre_pair == formsemestre
|
||||
assert formsemestre.query_ues_parcours_etud(etud.id).all() == deca.ues_pair
|
||||
assert deca.inscription_etat == scu.INSCRIT
|
||||
assert deca.inscription_etat_impair == scu.INSCRIT
|
||||
assert (deca.parcour is None) or (
|
||||
deca.parcour.id in {p.id for p in formsemestre.parcours}
|
||||
)
|
||||
|
||||
nb_ues = (
|
||||
len(deca.formsemestre_pair.query_ues_parcours_etud(etud.id).all())
|
||||
if deca.formsemestre_pair
|
||||
else 0
|
||||
)
|
||||
nb_ues += (
|
||||
len(deca.formsemestre_impair.query_ues_parcours_etud(etud.id).all())
|
||||
if deca.formsemestre_impair
|
||||
else 0
|
||||
)
|
||||
assert len(deca.decisions_ues) == nb_ues
|
||||
|
||||
nb_ues_un_sem = (
|
||||
len(deca.formsemestre_impair.query_ues_parcours_etud(etud.id).all())
|
||||
if deca.formsemestre_impair
|
||||
else len(deca.formsemestre_pair.query_ues_parcours_etud(etud.id).all())
|
||||
)
|
||||
assert len(deca.niveaux_competences) == nb_ues_un_sem
|
||||
assert deca.nb_competences == nb_ues_un_sem
|
||||
|
||||
|
||||
def _test_but_jury(formsemestre: FormSemestre, doc: dict):
|
||||
"""Test jurys
|
||||
Vérifie les champs de DecisionsProposeesAnnee et UEs
|
||||
"""
|
||||
for etud in formsemestre.etuds:
|
||||
deca = DecisionsProposeesAnnee(etud, formsemestre)
|
||||
doc_formsemestre = doc["Etudiants"][etud.nom]["formsemestres"][
|
||||
formsemestre.titre
|
||||
]
|
||||
assert doc_formsemestre
|
||||
if "attendu" in doc_formsemestre:
|
||||
if "deca" in doc_formsemestre["attendu"]:
|
||||
deca_att = doc_formsemestre["attendu"]["deca"]
|
||||
yaml_setup.compare_decisions_annee(deca, deca_att)
|
||||
formsemestre_validation_auto_but(
|
||||
formsemestre, only_adm=False, no_overwrite=False
|
||||
)
|
||||
yaml_setup.test_but_jury(formsemestre, doc)
|
||||
|
@ -1,7 +1,45 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
Met en place une base pour les tests, à partir d'une description YAML
|
||||
qui peut donner la formation, son ref. compétences, les formsemestres,
|
||||
les étudiants et leurs notes.
|
||||
Met en place une base pour les tests unitaires, à partir d'une description
|
||||
YAML qui peut donner la formation, son ref. compétences, les formsemestres,
|
||||
les étudiants et leurs notes et décisions de jury.
|
||||
|
||||
Le traitement est effectué dans l'ordre suivant:
|
||||
|
||||
setup_from_yaml()
|
||||
|
||||
- setup_but_formation():
|
||||
- import de la formation (le test utilise une seule formation)
|
||||
- associe_ues_et_parcours():
|
||||
- crée les associations formation <-> référentiel de compétence
|
||||
- setup_formsemestres()
|
||||
- crée les formsemestres décrits dans le YAML
|
||||
avec tous les modules du semestre ou des parcours si indiqués
|
||||
et une évaluation dans chaque moduleimpl.
|
||||
- inscrit_les_etudiants()
|
||||
- inscrit et place dans les groupes de parcours
|
||||
- note_les_modules()
|
||||
- saisie de toutes les notes indiquées dans le YAML
|
||||
|
||||
check_deca_fields()
|
||||
- vérifie les champs du deca (nb UE, compétences, ...) mais pas les décisions de jury.
|
||||
|
||||
formsemestre_validation_auto_but(only_adm=False)
|
||||
- enregistre toutes les décisions "par défaut" proposées (pas seulement les ADM)
|
||||
|
||||
test_but_jury()
|
||||
- compare décisions attendues indiquées dans le YAML avec celles de ScoDoc
|
||||
et enregistre immédiatement après la décision manuelle indiquée par `decision_jury`
|
||||
dans le YAML.
|
||||
|
||||
|
||||
Les tests unitaires associés sont généralement lents (construction de la base),
|
||||
et donc marqués par `@pytest.mark.slow`.
|
||||
"""
|
||||
|
||||
import os
|
||||
@ -352,7 +390,7 @@ def _check_decisions_ues(
|
||||
decisions_ues: dict[int, DecisionsProposeesUE], decisions_ues_att: dict[str:dict]
|
||||
):
|
||||
"""Vérifie les décisions d'UE
|
||||
pui enregistre décision manuelle si indiquée.
|
||||
puis enregistre décision manuelle si indiquée dans le YAML.
|
||||
"""
|
||||
for acronyme, dec_ue_att in decisions_ues_att.items():
|
||||
# retrouve l'UE
|
||||
@ -410,11 +448,18 @@ def _check_decisions_rcues(
|
||||
dec_rcue.rcue.est_compensable()
|
||||
== dec_rcue_att["rcue"]["est_compensable"]
|
||||
)
|
||||
# Force décision de jury:
|
||||
code_manuel = dec_rcue_att.get("decision_jury")
|
||||
if code_manuel is not None:
|
||||
assert code_manuel in dec_rcue.codes
|
||||
dec_rcue.record(code_manuel)
|
||||
|
||||
|
||||
def compare_decisions_annee(deca: DecisionsProposeesAnnee, deca_att: dict):
|
||||
"""Vérifie que les résultats de jury calculés sont ceux attendus,
|
||||
"""Vérifie que les résultats de jury calculés pour l'année, les RCUEs et les UEs
|
||||
sont ceux attendus,
|
||||
puis enregistre les décisions manuelles indiquées dans le YAML.
|
||||
|
||||
deca est le résultat calculé par ScoDoc
|
||||
deca_att est un dict lu du YAML
|
||||
"""
|
||||
@ -435,3 +480,70 @@ def compare_decisions_annee(deca: DecisionsProposeesAnnee, deca_att: dict):
|
||||
_check_decisions_rcues(
|
||||
deca.decisions_rcue_by_niveau.values(), deca_att["decisions_rcues"]
|
||||
)
|
||||
# Force décision de jury:
|
||||
code_manuel = deca_att.get("decision_jury")
|
||||
if code_manuel is not None:
|
||||
assert code_manuel in deca.codes
|
||||
deca.record(code_manuel)
|
||||
assert deca.recorded
|
||||
|
||||
|
||||
def check_deca_fields(formsemestre: FormSemestre, etud: Identite = None):
|
||||
"""Vérifie les champs principaux (inscription, nb UE, nb compétences)
|
||||
de l'instance de DecisionsProposeesAnnee.
|
||||
Ne vérifie pas les décisions de jury proprement dites.
|
||||
Si etud n'est pas spécifié, prend le premier inscrit trouvé dans le semestre.
|
||||
"""
|
||||
etud = etud or formsemestre.etuds.first()
|
||||
assert etud # il faut au moins un étudiant dans le semestre
|
||||
deca = DecisionsProposeesAnnee(etud, formsemestre)
|
||||
assert deca.validation is None # pas encore de validation enregistrée
|
||||
assert False is deca.recorded
|
||||
assert deca.code_valide is None
|
||||
if formsemestre.semestre_id % 2:
|
||||
assert deca.formsemestre_impair == formsemestre
|
||||
assert formsemestre.query_ues_parcours_etud(etud.id).all() == deca.ues_impair
|
||||
else:
|
||||
assert deca.formsemestre_pair == formsemestre
|
||||
assert formsemestre.query_ues_parcours_etud(etud.id).all() == deca.ues_pair
|
||||
assert deca.inscription_etat == scu.INSCRIT
|
||||
assert deca.inscription_etat_impair == scu.INSCRIT
|
||||
assert (deca.parcour is None) or (
|
||||
deca.parcour.id in {p.id for p in formsemestre.parcours}
|
||||
)
|
||||
|
||||
nb_ues = (
|
||||
len(deca.formsemestre_pair.query_ues_parcours_etud(etud.id).all())
|
||||
if deca.formsemestre_pair
|
||||
else 0
|
||||
)
|
||||
nb_ues += (
|
||||
len(deca.formsemestre_impair.query_ues_parcours_etud(etud.id).all())
|
||||
if deca.formsemestre_impair
|
||||
else 0
|
||||
)
|
||||
assert len(deca.decisions_ues) == nb_ues
|
||||
|
||||
nb_ues_un_sem = (
|
||||
len(deca.formsemestre_impair.query_ues_parcours_etud(etud.id).all())
|
||||
if deca.formsemestre_impair
|
||||
else len(deca.formsemestre_pair.query_ues_parcours_etud(etud.id).all())
|
||||
)
|
||||
assert len(deca.niveaux_competences) == nb_ues_un_sem
|
||||
assert deca.nb_competences == nb_ues_un_sem
|
||||
|
||||
|
||||
def test_but_jury(formsemestre: FormSemestre, doc: dict):
|
||||
"""Test jurys BUT
|
||||
Vérifie les champs de DecisionsProposeesAnnee et UEs
|
||||
"""
|
||||
for etud in formsemestre.etuds:
|
||||
deca = DecisionsProposeesAnnee(etud, formsemestre)
|
||||
doc_formsemestre = doc["Etudiants"][etud.nom]["formsemestres"][
|
||||
formsemestre.titre
|
||||
]
|
||||
assert doc_formsemestre
|
||||
if "attendu" in doc_formsemestre:
|
||||
if "deca" in doc_formsemestre["attendu"]:
|
||||
deca_att = doc_formsemestre["attendu"]["deca"]
|
||||
compare_decisions_annee(deca, deca_att)
|
||||
|
Loading…
Reference in New Issue
Block a user