feat: BIO_NORMALS 33 analytes + interprétations cliniques + cohérence DAS/bio étendue

- BIO_NORMALS passe de 13 à 33 tests (cardio, infectio, métabo, thyroïde, hémato, hépatique)
- _BIO_INTERPRETATION synchronisé (33 entrées, 3 clés high/low/normal chacune)
- _DAS_BIO_CHECKS étendu de 13 à 38 patterns (sepsis, infarctus, EP, diabète, thyroïde, etc.)
- lab_value_sanity.yaml étendu avec 20 garde-fous plausibilité nouveaux tests
- tests/test_bio_normals.py : 32 tests (complétude, concordance, _is_abnormal)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dom
2026-02-20 11:00:53 +01:00
parent 3c070f3c1d
commit 1a3c523987
4 changed files with 318 additions and 9 deletions

134
tests/test_bio_normals.py Normal file
View File

@@ -0,0 +1,134 @@
"""Tests unitaires pour les plages de référence biologiques."""
import pytest
from src.medical.bio_normals import BIO_NORMALS, _is_abnormal
from src.control.cpam_context import _BIO_INTERPRETATION
class TestBioNormalsCompleteness:
"""Vérifie la complétude et la cohérence de BIO_NORMALS."""
def test_has_33_analytes(self):
assert len(BIO_NORMALS) == 33
def test_all_tuples_are_valid(self):
for name, (lo, hi) in BIO_NORMALS.items():
assert isinstance(lo, (int, float)), f"{name}: lo doit être numérique"
assert isinstance(hi, (int, float)), f"{name}: hi doit être numérique"
assert lo <= hi, f"{name}: lo ({lo}) > hi ({hi})"
def test_known_analytes_present(self):
expected = {
"CRP", "Hémoglobine", "Plaquettes", "Leucocytes", "Créatinine",
"Sodium", "Potassium", "ASAT", "ALAT", "GGT", "PAL",
"Bilirubine totale", "Lipasémie",
# Nouveaux Phase 5
"Troponine", "BNP", "NT-proBNP", "D-dimères", "INR", "Fibrinogène",
"Procalcitonine", "Lactate", "Glycémie", "HbA1c", "Albumine",
"Urée", "Acide urique", "TP", "TCA", "Ferritine", "LDH",
"Bilirubine directe", "TSH", "VS",
}
assert set(BIO_NORMALS.keys()) == expected
class TestBioInterpretationConcordance:
"""Vérifie que BIO_NORMALS et _BIO_INTERPRETATION sont synchronisés."""
def test_every_normal_has_interpretation(self):
missing = set(BIO_NORMALS) - set(_BIO_INTERPRETATION)
assert not missing, f"BIO_NORMALS sans interprétation: {missing}"
def test_every_interpretation_has_normal(self):
extra = set(_BIO_INTERPRETATION) - set(BIO_NORMALS)
assert not extra, f"Interprétation sans BIO_NORMALS: {extra}"
def test_all_interpretations_have_three_keys(self):
for name, interp in _BIO_INTERPRETATION.items():
assert "high" in interp, f"{name}: manque 'high'"
assert "low" in interp, f"{name}: manque 'low'"
assert "normal" in interp, f"{name}: manque 'normal'"
class TestIsAbnormal:
"""Tests pour _is_abnormal() sur les nouveaux et anciens analytes."""
def test_crp_high(self):
assert _is_abnormal("CRP", "180") is True
def test_crp_normal(self):
assert _is_abnormal("CRP", "3") is False
def test_hemoglobine_low(self):
assert _is_abnormal("Hémoglobine", "8.5") is True
def test_hemoglobine_normal(self):
assert _is_abnormal("Hémoglobine", "14.5") is False
# Nouveaux analytes
def test_troponine_high(self):
assert _is_abnormal("Troponine", "0.15") is True
def test_troponine_normal(self):
assert _is_abnormal("Troponine", "0.02") is False
def test_bnp_high(self):
assert _is_abnormal("BNP", "500") is True
def test_bnp_normal(self):
assert _is_abnormal("BNP", "50") is False
def test_lactate_high(self):
assert _is_abnormal("Lactate", "4.5") is True
def test_lactate_normal(self):
assert _is_abnormal("Lactate", "1.2") is False
def test_glycemie_high(self):
assert _is_abnormal("Glycémie", "8.0") is True
def test_glycemie_low(self):
assert _is_abnormal("Glycémie", "2.5") is True
def test_glycemie_normal(self):
assert _is_abnormal("Glycémie", "4.5") is False
def test_tsh_high(self):
assert _is_abnormal("TSH", "10.0") is True
def test_tsh_low(self):
assert _is_abnormal("TSH", "0.1") is True
def test_tsh_normal(self):
assert _is_abnormal("TSH", "2.5") is False
def test_inr_high(self):
assert _is_abnormal("INR", "3.5") is True
def test_inr_normal(self):
assert _is_abnormal("INR", "1.0") is False
def test_albumine_low(self):
assert _is_abnormal("Albumine", "20") is True
def test_albumine_normal(self):
assert _is_abnormal("Albumine", "42") is False
def test_ferritine_low(self):
assert _is_abnormal("Ferritine", "5") is True
def test_ferritine_normal(self):
assert _is_abnormal("Ferritine", "150") is False
# Valeurs textuelles
def test_text_negative(self):
assert _is_abnormal("CRP", "négative") is False
def test_text_positive(self):
assert _is_abnormal("CRP", "positive") is True
def test_unknown_test(self):
assert _is_abnormal("TestInconnu", "42") is None
def test_unparseable_value(self):
assert _is_abnormal("CRP", "non dosé") is None