airflow-dags/tests/README.md
Pascal Beyer 82c393408f
Some checks failed
ETL-QS / etl-tests (push) Failing after 44s
ETL-QS-Suite, CI-Pipeline und korrigierte Pfade/DB
- Pfad-Defaults im DAG auf das Repo-Checkout /opt/airflow/git/current
  umgestellt (include-Skripte + etl_cache) und Ziel-DB auf
  analytics_pg_duckdb festgelegt
- tests/: Fixture-Generator (>=4 Dateien je Quell-Ordner mit Dubletten/
  Edge-Cases) und End-to-End-Runner mit 45 Pruefungen gegen erwartete
  Ergebnisse, inkl. README
- .forgejo/workflows: CI laeuft die ETL-QS bei Aenderungen an ETL-Skript,
  tests/ oder Geo-Referenz (python:3.12-Container, runs-on docker)
- .gitignore: .venv_test/ und generierte tests/fixtures/ ausgeschlossen

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 14:11:55 +02:00

4.5 KiB

Qualitätssicherung HVB-ETL

Tests für die Transformationslogik in include/02_etl_angebote_zuschlaege.py.

Die Suite erzeugt deterministische Excel-Eingabedaten (≥4 Dateien je Quell-Ordner, inkl. Dubletten und Edge-Cases), führt das ETL-Skript real aus und prüft die erzeugten Output-CSVs gegen exakt berechnete Erwartungswerte.

Ausführen

# Einmalig: Umgebung (Python ≥ 3.10, das ETL nutzt `str | None`-Syntax)
python3.12 -m venv .venv_test
.venv_test/bin/pip install pandas openpyxl

# Komplette QS (erzeugt Fixtures, läuft ETL, prüft Ergebnisse):
.venv_test/bin/python tests/run_tests.py

Exit-Code 0 = alle Prüfungen bestanden (CI-tauglich). Bei Fehlern bleibt das temporäre Arbeitsverzeichnis zur Analyse erhalten; bei Erfolg wird es gelöscht.

Nur die Eingabedaten erzeugen (ohne ETL/Prüfung):

.venv_test/bin/python tests/generate_fixtures.py   # -> tests/fixtures/input/

Dateien

Datei Zweck
generate_fixtures.py Erzeugt die Excel-Testdaten (4 Dateien/Ordner).
run_tests.py Baut Workdir, führt ETL aus, 45 Prüfungen.
fixtures/ Generierte Eingabedaten (nicht versioniert).

Testdatensatz (Soll-Bild)

9 Angebote (6 aus Export, 3 nur aus Archiv), 8 eindeutige Kunden, 3 Zuschläge.

taifun_export/ — 4 Dateien, „jüngster Export gewinnt"

  • A-1001 liegt in 3 Dateien (Stände 500/2000/4000 via _dateistand.csv). Erwartung: jüngste Version (Stand 4000) gewinnt → Beschreibung „1000 m³", Kunde „Müller GmbH". 8 Rohzeilen → 6 eindeutige Angebote.
  • A-1004: Kundenadresse leer, nur Standort „80331 München" → Standortadresse hat Vorrang (adress_quelle = standort).
  • A-1006: Land CH, PLZ „1010 Wien" (kein dt. Format) → kein Geo-Treffer.

pflege/ — 4 Dateien, UNION + gültiger Status

  • 8 Status-Events → 7 nach Dedup (A-1003/Auftrag exakt doppelt).
  • A-1001: neuestes Datum 2024-03-05 mit Gleichstand „Verhandlung" (Rang 3) vs. „Angebot" (Rang 2) → höherer Rang gewinnt: Verhandlung (Ampel orange).
  • A-1003: Pflege „Auftrag" überschreibt Export-Abbruchtext → Auftrag (grün).
  • A-9999: Waisen-Status ohne Angebot → erscheint in staging_status_historie, nicht in staging_angebote.

archiv/ — 4 Dateien, Alt-Angebote ergänzen

  • B-9001/9002/9003 nicht im Export → werden als herkunft_stamm = archiv ergänzt. B-9001 über zwei Dateien dupliziert → nur einmal.
  • A-1002 ist bereits im Export → Archiv-Version wird verworfen (Export-Kunde „Bauer AG" bleibt, nicht „Bauer AG ARCHIV").

Status-Ableitung (ohne Pflege)

  • A-1004: gültige Projektnummer P-67890, keine Pflege → Auftrag (status_quelle = export_projekt).
  • A-1006: Projekttext „kein Interesse" (kein Muster) → Abgelehnt (schwarz).
  • A-1005: weder Pflege noch Projekt → Default Angebot (gelb).
  • Status-Konflikt: A-1002 hat Projektnummer P-12345, Pflege sagt aber „Angebot" → status_konflikt = True (genau 1 Konflikt).

Kunden-Dedup

  • „Müller GmbH | 70001" = A-1001 + A-1005 → 1 Kunde, aktuellstes Angebot = A-1005 (jüngstes Datum). Gesamt 8 eindeutige Kunden.

zuschlaege/ — 4 Dateien, zwei Blätter, Kopfzeile in Zeile 4

  • Blätter Zuschläge_Detailliert + Zuschläge_Kompakt (jeweils header=3).
  • 6 Detailzeilen → 5 nach Dedup je (Zuschlags-Nr, Flurstück); Z-100/F1 doppelt. 3 eindeutige Zuschläge.
  • Gebotsmenge wird aus dem Kompakt-Blatt gemerged (Z-100 → 5000).
  • PLZ 04109 behält die führende Null.
  • plz_mit_eigenem_angebot: 10115 (eigenes Angebot) → True; 99999 → False.
  • Lead-Ampel durchgängig lila.

Erwartete Kennzahlen (Übersicht)

Output-CSV Zeilen Kernaussage
staging_angebote 9 6 Export + 3 Archiv, Nummern eindeutig
staging_status_historie 7 inkl. Waise A-9999, Dublette entfernt
staging_zuschlaege 5 3 eindeutige Zuschläge
v_angebote_karte 9 8/9 mit Koordinaten (A-1006 Ausland ohne)
v_angebote_karte_aktuell 8 1 Zeile je Kunde
v_kunden_pipeline 8 Top-Kunde Müller GmbH (2 Angebote)
v_zuschlaege_karte 5 4/5 mit Koordinaten, Ampel lila

Status-Verteilung: Angebot 5, Auftrag 2, Verhandlung 1, Abgelehnt 1.

Hinweis: Die Geo-Prüfungen nutzen etl_cache/geo_plz_koordinaten.csv. Diese Datei hat keine Spalte kreis, daher bleibt landkreis im Test leer — das ist erwartet und wird vom ETL korrekt behandelt.