def mit_einlagerung(bestand, artikel, menge): """Neuer Bestand mit zusätzlicher Menge. Mutiert nichts.""" return {**bestand, artikel: bestand.get(artikel, 0) + menge} def mit_entnahme(bestand, artikel, menge): """(neuer Bestand, erfolgreich?) - bei zu wenig Bestand bleibt alles gleich.""" if bestand.get(artikel, 0) < menge: return bestand, False return {**bestand, artikel: bestand[artikel] - menge}, True
def lauf(): bestand = {} protokoll = [] bestand = mit_einlagerung(bestand, "maus", 5) protokoll.append("+5 maus") print(f"maus: {bestand['maus']}") bestand = mit_einlagerung(bestand, "maus", 3) protokoll.append("+3 maus") print(f"maus: {bestand['maus']}") bestand, ok = mit_entnahme(bestand, "maus", 2) if ok: protokoll.append("-2 maus") else: print("zu wenig Bestand") bestand, ok = mit_entnahme(bestand, "maus", 99) if not ok: print("zu wenig Bestand") return bestand, protokoll
lauf() -> ({'maus': 6}, ['+5 maus', '+3 maus', '-2 maus'])
Identisch zum Verhalten vorher.
def test_kein_seiteneffekt(): original = {"maus": 5} neu = mit_einlagerung(original, "maus", 3) assert neu == {"maus": 8} assert original == {"maus": 5} # Original unverändert def test_deterministisch(): bestand = {"maus": 5} assert mit_entnahme(bestand, "maus", 2) == mit_entnahme(bestand, "maus", 2) def test_zu_wenig_bestand(): assert mit_entnahme({"maus": 1}, "maus", 99) == ({"maus": 1}, False)
Der Test test_deterministisch würde mit der alten Fassung scheitern: Dort liefert der zweite Aufruf einen anderen Bestand als der erste.
(bestand, ok). Alternativ eine frozen Dataclass Ergebnis(bestand, erfolgreich, meldung), wenn mehr Information nötig wird.lager und protokoll vor jedem Test zurückgesetzt werden - vergisst man das, hängen die Tests voneinander ab.In Flask ist dieses Muster die Regel und nicht die Ausnahme: Die Route liest den Request und schreibt die Response (Schale), die Berechnung liegt in pure Funktionen, die ohne laufenden Server getestet werden können.