====== LU07.L07 - Sicherheitsnetz zuerst ====== ===== Schritt 1: Verhalten erkunden ===== notenschnitt([18, 20, 16], 20) -> 5.5 notenschnitt([0, 0], 20) -> 1.0 notenschnitt([20, 20], 20) -> 6.0 notenschnitt([25], 20) -> 6.0 (Deckelung greift) notenschnitt([10], 0) -> 1 (int, nicht float) notenschnitt([13, 14], 20) -> 4.5 notenschnitt([], 20) -> ZeroDivisionError ===== Schritt 2: Festhalten ===== import pytest from noten import notenschnitt @pytest.mark.parametrize("punkte, maximum, erwartet", [ ([18, 20, 16], 20, 5.5), ([0, 0], 20, 1.0), ([20, 20], 20, 6.0), ([25], 20, 6.0), ([10], 0, 1), ([13, 14], 20, 4.5), ]) def test_notenschnitt_bleibt_gleich(punkte, maximum, erwartet): assert notenschnitt(punkte, maximum) == erwartet def test_leere_liste_wirft_bisher(): with pytest.raises(ZeroDivisionError): notenschnitt([], 20) Der letzte Test ist der wichtigste: Auch ein Absturz ist Verhalten und muss festgehalten werden. Wer ihn beim Refactoring versehentlich «wegrepariert», ändert das Verhalten - und merkt es ohne diesen Test nicht. ===== Schritt 3: Refactoring ===== MIN_NOTE = 1 MAX_NOTE = 6 def auf_halbe_note(note): return round(note * 2) / 2 def notenschnitt(punkte, maximum): if maximum == 0: return MIN_NOTE erreichter_anteil = sum(punkte) / len(punkte) / maximum note = MIN_NOTE + (MAX_NOTE - MIN_NOTE) * erreichter_anteil return auf_halbe_note(min(note, MAX_NOTE)) Alle sieben Tests bleiben grün. Die Formel ''1 + 5 * ...'' ist jetzt als «lineare Skala von 1 bis 6» erkennbar, und ''auf_halbe_note'' beantwortet die Frage nach ''round(note * 2) / 2''. ===== Schritt 4: Bewertung ===== ^ Beobachtung ^ Fachlich problematisch? ^ Was wäre zu tun ^ | ''maximum = 0'' liefert 1 | ja - das ist stillschweigend eine Notengebung für eine unmögliche Situation | ''ValueError'' werfen, damit der Aufrufer den Konfigurationsfehler bemerkt | | ''[]'' wirft ''ZeroDivisionError'' | ja - die Meldung sagt nichts über den Fall aus | eigene Prüfung mit klarer Fehlermeldung | | ''1'' statt ''1.0'' | nein, in Python vergleichbar - kann aber in Ausgabe und JSON auffallen | ''float(MIN_NOTE)'' zurückgeben | | Punkte über dem Maximum werden auf 6 gedeckelt | je nach Reglement gewollt (Bonuspunkte) | mit der Fachseite klären | **Warum zuerst festhalten und nicht gleich reparieren?** Weil sonst zwei Änderungen gleichzeitig passieren. Wenn danach etwas nicht mehr stimmt, wissen Sie nicht, ob das Refactoring oder der Bugfix schuld ist. Die Reihenfolge lautet immer: festhalten, refactoren (Tests grün), dann in einem eigenen Commit das Verhalten bewusst ändern und den Test anpassen. ---- {{tag>M323-LU07 M323-D1I M323-D1A}} [[https://creativecommons.org/licenses/by-nc-sa/4.0/ch/|{{https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png}}]] (c) Kevin Maurizi