Add CI test-coverage gate at 80%, backfill remaining logic-module gaps
willemjan/glucose-dashboard/pipeline/head This commit looks good
willemjan/glucose-dashboard/pipeline/head This commit looks good
pytest-cov + pyproject.toml [tool.coverage.*] measure reporting.py, nightscout_client.py, data_processing.py, pdf_export.py, profile_data.py, ui_common.py, and auth.py; app.py and pages/*.py are omitted (thin Streamlit UI scripts, not meaningfully unit-testable without a running Streamlit session — the handful of similarly UI-coupled functions left in ui_common.py/auth.py are marked "# pragma: no cover" with the same rationale, since the logic they call into is already fully tested). The Gitea Actions test job now runs with --cov and fails the build below 80%; the coverage XML is uploaded as a build artifact and fed into the SonarQube scan (closing the gap flagged in homelab-cicd-werkinstructie.md). Backfilled a few missing branches (get_colors() theme fallback, secondary-y-axis overlay traces) to reach 98% on the measured modules — comfortable headroom above the 80% gate. Builds on #29/#30/#31.
This commit is contained in:
+27
-10
@@ -118,8 +118,12 @@ def get_colors() -> dict:
|
||||
return PALETTE["dark" if theme_type == "dark" else "light"]
|
||||
|
||||
|
||||
def select_period_days(default_label: str) -> tuple[date, date, int]:
|
||||
"""Periodekiezer voor rapportagepagina's; geeft (start, eind, aantal_dagen) terug."""
|
||||
def select_period_days(default_label: str) -> tuple[date, date, int]: # pragma: no cover
|
||||
"""Periodekiezer voor rapportagepagina's; geeft (start, eind, aantal_dagen) terug.
|
||||
|
||||
Pure Streamlit-widget-orkestratie (st.radio) — buiten scope van de
|
||||
unit-testdekking net als pages/*.py, zie pyproject.toml se coverage-omit-lijst.
|
||||
"""
|
||||
labels = list(PERIOD_OPTIONS_DAYS.keys())
|
||||
label = st.radio("Periode", labels, index=labels.index(default_label), horizontal=True)
|
||||
days = PERIOD_OPTIONS_DAYS[label]
|
||||
@@ -129,11 +133,15 @@ def select_period_days(default_label: str) -> tuple[date, date, int]:
|
||||
|
||||
|
||||
@st.cache_data(ttl=3600, show_spinner="Data ophalen van Nightscout...")
|
||||
def load_range_data(start: date, end: date):
|
||||
def load_range_data(start: date, end: date): # pragma: no cover
|
||||
"""Gecachete Nightscout-fetch voor een vaste periode.
|
||||
|
||||
Lange TTL (in tegenstelling tot de 60s van de live-pagina): historische
|
||||
data van een afgeronde periode verandert niet.
|
||||
|
||||
Dunne st.cache_data-wrapper rond al-geteste fetch_entries_range()/
|
||||
fetch_treatments_range() — buiten scope van de unit-testdekking net als
|
||||
pages/*.py, zie pyproject.toml se coverage-omit-lijst.
|
||||
"""
|
||||
glucose = fetch_entries_range(start, end)
|
||||
treatments = fetch_treatments_range(start, end)
|
||||
@@ -141,10 +149,14 @@ def load_range_data(start: date, end: date):
|
||||
|
||||
|
||||
@st.cache_data(ttl=21600, show_spinner="Profiel ophalen van Nightscout...")
|
||||
def load_profile() -> dict:
|
||||
def load_profile() -> dict: # pragma: no cover
|
||||
"""Gecachete profiel-fetch. Langere TTL dan load_range_data (6 uur i.p.v.
|
||||
1 uur): een pompprofiel wijzigt zelden, in tegenstelling tot glucose-/
|
||||
behandeldata van een lopende periode."""
|
||||
behandeldata van een lopende periode.
|
||||
|
||||
Dunne st.cache_data-wrapper rond al-geteste fetch_profile()/parse_profile()
|
||||
— buiten scope van de unit-testdekking net als pages/*.py.
|
||||
"""
|
||||
raw = fetch_profile()
|
||||
return parse_profile(raw)
|
||||
|
||||
@@ -363,19 +375,21 @@ def add_target_line_trace(
|
||||
)
|
||||
|
||||
|
||||
def render_completeness_warning(glucose: pd.DataFrame, start: date, end: date) -> None:
|
||||
def render_completeness_warning(glucose: pd.DataFrame, start: date, end: date) -> None: # pragma: no cover
|
||||
"""Toon reporting.completeness_warning()'s oordeel als st.warning, indien nodig.
|
||||
|
||||
Gebruikt door elke rapportagepagina, direct na de load_range_data-call.
|
||||
De beoordelingslogica zelf staat in reporting.py (pure functie) zodat het
|
||||
PDF-rapport (pdf_export.py) exact dezelfde disclaimer kan hergebruiken.
|
||||
De beoordelingslogica zelf staat in reporting.py (pure functie, wél volledig
|
||||
getest) zodat het PDF-rapport (pdf_export.py) exact dezelfde disclaimer kan
|
||||
hergebruiken. Deze functie is alleen de st.warning-weergave — buiten scope
|
||||
van de unit-testdekking net als pages/*.py.
|
||||
"""
|
||||
message = completeness_warning(glucose, start, end)
|
||||
if message:
|
||||
st.warning(message)
|
||||
|
||||
|
||||
def render_event_level(
|
||||
def render_event_level( # pragma: no cover
|
||||
glucose: pd.DataFrame,
|
||||
threshold: float,
|
||||
direction: str,
|
||||
@@ -386,7 +400,10 @@ def render_event_level(
|
||||
"""Render de metrics/tabel/tijdstip-histogram voor één hypo-/hyperniveau.
|
||||
|
||||
Gedeeld tussen de Hypo Events- en Hyper Events-pagina's (FR5/FR6), die
|
||||
elk twee niveaus (Level 1/Level 2) op dezelfde manier tonen.
|
||||
elk twee niveaus (Level 1/Level 2) op dezelfde manier tonen. Pure
|
||||
Streamlit-widget-weergave rond al-geteste reporting.detect_events()/
|
||||
summarize_events() — buiten scope van de unit-testdekking net als
|
||||
pages/*.py.
|
||||
"""
|
||||
events = detect_events(glucose, threshold, direction)
|
||||
summary = summarize_events(events, period_days)
|
||||
|
||||
Reference in New Issue
Block a user