Ein Programm, das heute läuft, kann morgen nach einer kleinen Änderung kaputt sein. Automatische Tests prüfen deinen Code auf Knopfdruck. Sie sind das Sicherheitsnetz, mit dem du ohne Angst ändern kannst.
Die Idee
Du schreibst kleine Funktionen, die deinen Code mit bekannten Eingaben aufrufen und das Ergebnis mit der erwarteten Ausgabe vergleichen. Stimmt etwas nicht, schlägt der Test fehl.
Der einfachste Test ist assert:
def addiere(a, b):
return a + b
assert addiere(2, 3) == 5
assert addiere(-1, 1) == 0
print("alle Prüfungen bestanden")
try:
assert addiere(2, 2) == 5, "2 + 2 sollte 4 sein"
except AssertionError as e:
print("Fehler:", e)alle Prüfungen bestanden Fehler: 2 + 2 sollte 4 sein
unittest (Standardbibliothek)
import unittest
def ist_primzahl(n):
if n < 2:
return False
return all(n % t for t in range(2, int(n ** 0.5) + 1))
class TestPrimzahl(unittest.TestCase):
def test_primzahlen(self):
for p in (2, 3, 5, 7, 11):
self.assertTrue(ist_primzahl(p))
def test_keine_primzahlen(self):
for n in (0, 1, 4, 9, 15):
self.assertFalse(ist_primzahl(n))
def test_fehler(self):
with self.assertRaises(TypeError):
ist_primzahl("a")
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestPrimzahl)
ergebnis = unittest.TextTestRunner(verbosity=0, stream=open("/dev/null", "w")).run(suite)
print("Tests:", ergebnis.testsRun, "Fehler:", len(ergebnis.failures) + len(ergebnis.errors))Tests: 3 Fehler: 0
In einer eigenen Datei test_irgendwas.py genügt am Ende:
if __name__ == "__main__":
unittest.main()Oder du startest alle Tests mit python -m unittest. Wichtige Prüfmethoden:
| Methode | Prüft |
|---|---|
assertEqual(a, b) | a == b |
assertTrue(x) / assertFalse(x) | Wahrheitswert |
assertIn(a, b) | a in b |
assertAlmostEqual(a, b) | fast gleich (Kommazahlen) |
assertRaises(Fehler) | löst die Ausnahme aus |
pytest
pytest (pip install pytest) ist der beliebteste Testrunner. Tests sind einfache Funktionen mit assert, und bei Fehlern zeigt pytest sehr genau, was abwich:
# datei: test_rechnen.py
def test_addition():
assert 1 + 1 == 2
def test_division_durch_null():
import pytest
with pytest.raises(ZeroDivisionError):
1 / 0Ausführen im Terminal:
pytest # alle Tests im Projekt
pytest -v # ausführliche Ausgabe
pytest -k primzahl # nur Tests, deren Name "primzahl" enthältParametrisierte Tests
Mit @pytest.mark.parametrize läuft derselbe Test mit vielen Eingaben:
import pytest
@pytest.mark.parametrize("n, erwartet", [(2, True), (4, False), (13, True)])
def test_prim(n, erwartet):
assert ist_primzahl(n) == erwartetFixtures
Fixtures liefern wiederverwendbare Testdaten oder Vorbereitungen:
import pytest
@pytest.fixture
def warenkorb():
return {"Apfel": 2, "Birne": 1}
def test_menge(warenkorb):
assert sum(warenkorb.values()) == 3Was testet man?
- Normale Fälle (das erwartete Verhalten)
- Grenzfälle: leere Liste, Null, negative Zahlen, sehr große Werte
- Fehlerfälle: Was passiert bei falscher Eingabe?
- Jeden Fehler, den du gefunden hast, als Test festhalten, damit er nicht zurückkommt
Merke
- Tests prüfen automatisch, ob Code das Erwartete tut
assertist der einfachste Test,unittestist eingebaut- pytest: Funktionen mit
assert,parametrizeund Fixtures - Teste normale Fälle, Grenzfälle und Fehlerfälle
- Jeder gefundene Fehler wird zum Test
Aufgabe
Schreibe eine Funktion ist_palindrom(text) und mindestens fünf Tests dafür, darunter Groß-/Kleinschreibung und den leeren Text.