Kapitel 09 • Softwarequalität & TDD

Eigene Unit Tests schreiben & TDD 🧪🛡️

Lerne, wie du deinen Code mit Pythons unittest absicherst, Test-Driven Development anwendest und Fehler sofort entlarvst.

1. Warum schreiben Profis eigene Unit Tests?

Bisher hast du deine Programme vermutlich getestet, indem du print()-Befehle geschrieben hast und per Auge überprüft hast, ob das Ergebnis stimmt. Das Problem: Bei 100 Funktionen vergisst man leicht Randfälle, und wenn man eine Zeile ändert, merkt man oft nicht, dass man an anderer Stelle etwas kaputtgemacht hat (eine sogenannte Regression).

🪂 Das automatische Sicherheitsnetz:
Ein Unit Test ist ein kleines Testprogramm, das eine einzelne Funktion oder Methode isoliert prüft. Es vergleicht das tatsächliche Ergebnis automatisch mit dem Soll-Wert. Läuft dein Code in 0.01 Sekunden durch 50 Tests, kannst du jederzeit mit 100%iger Sicherheit sagen: "Mein Code funktioniert fehlerfrei!"

Der TDD-Entwicklungszyklus (Red • Green • Refactor)

In der agilen Entwicklung nutzt man oft Test-Driven Development (TDD):

🔴 1. Red (Test schreiben)

Du schreibst zuerst den Test für ein Feature, das es noch gar nicht gibt. Der Test schlägt rot fehl.

🟢 2. Green (Code schreiben)

Du implementierst genau so viel Code, dass der Test grün wird.

🔵 3. Refactor (Aufräumen)

Du verbesserst den Code, machst ihn lesbarer und schneller – abgesichert durch deine Tests.

2. Der Aufbau einer unittest-Klasse

Python bringt ein komplettes Testframework bereits mit: import unittest.

Struktur einer Testklasse in Python
import unittest

class TestTaschenrechner(unittest.TestCase):

    def setUp(self):
        # Wird AUTOMATISCH vor JEDEM einzelnen Test ausgeführt!
        self.calc = Taschenrechner()

    def test_addition(self):
        # WICHTIG: Jede Testmethode MUSS mit "test_" beginnen!
        ergebnis = self.calc.add(2, 3)
        self.assertEqual(ergebnis, 5)

if __name__ == "__main__":
    unittest.main(verbosity=2)
💡 Warum setUp() so genial ist:
In setUp() erstellst du frische Objekte für jeden Testlauf. Dadurch beeinflussen sich Tests niemals gegenseitig (Test-Isolation).

3. Die wichtigsten Assert-Methoden im Überblick

In deinen Testmethoden verwendest du self.assert...(), um Bedingungen zu prüfen:

Assert-Methode Bedeutung Code-Beispiel
self.assertEqual(a, b) Prüft $a == b$ self.assertEqual(calc.add(2, 3), 5)
self.assertNotEqual(a, b) Prüft $a \ne b$ self.assertNotEqual(konto.stand, 0)
self.assertAlmostEqual(a, b, places=2) Prüft Kommazahlen mit Rundung self.assertAlmostEqual(10/3, 3.333, places=2)
self.assertTrue(x) / assertFalse(x) Prüft Booleschen Wert self.assertTrue(konto.ist_aktiv)
self.assertIn(item, liste) Prüft, ob Element in Liste/String ist self.assertIn(50.0, konto.transaktionen)
self.assertIsNone(x) / assertIsNotNone(x) Prüft is None self.assertIsNone(person.mutter)
with self.assertRaises(FehlerTyp): Prüft, ob eine Exception geworfen wird with self.assertRaises(ValueError): konto.abheben(9999)

Fehler & Exceptions testen mit assertRaises

Beispiel: Testen auf erwartete Abstürze / Fehler
def test_division_durch_null(self):
    # Der Test besteht NUR dann, wenn innerhalb des with-Blocks
    # tatsächlich ein ZeroDivisionError ausgelöst wird!
    with self.assertRaises(ZeroDivisionError):
        self.calc.div(10, 0)

4. 🎯 Deine Aufgaben in aufgabe.py

In 09_eigene_unit_tests_schreiben/aufgabe.py sind die Klassen Taschenrechner und Bankkonto bereits fertig vorgegeben. Deine Aufgabe ist es, die Unit-Test-Klassen zu schreiben!

💡 Lösungshinweise (Aufklappen bei Bedarf)

🔍 Tipp zu TODO 3 (Periodische Kommazahlen testen)

Weil 10 / 3 = 3.3333333333333335 im Computer nicht exakt dargestellt werden kann, vergleicht man mit Rundungstoleranz:

self.assertAlmostEqual(self.calc.div(10, 3), 3.3333, places=2)
🔍 Tipp zu TODO 8 & 10 (Transaktionen mit assertIn prüfen)
self.k1.einzahlen(50.0)
self.assertEqual(self.k1.kontostand, 150.0)
self.assertIn(50.0, self.k1.transaktionen)

5. 🧪 Deine Tests ausführen & validieren

Schritt 1: Führe deine eigenen Tests im Terminal aus:

Terminal (Eigene Tests starten)
python3 aufgabe.py

Schritt 2: Validiere deine Tests mit dem Metatest-Skript (prüft, ob deine Tests auch fehlerhaften Code entlarven!):

Terminal (Metatests prüfen)
python3 test_aufgabe.py