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).
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.
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)
setUp() so genial ist: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
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:
python3 aufgabe.py
Schritt 2: Validiere deine Tests mit dem Metatest-Skript (prüft, ob deine Tests auch fehlerhaften Code entlarven!):
python3 test_aufgabe.py