← Zurück zum Blog
TestingPython27. Mai 2026· 13 min Lesezeit

Mocking & Patching: externe Abhängigkeiten in Tests isolieren

Inhalt
  1. Warum mocken?
  2. patch als Decorator & Context Manager
  3. MagicMock: Rückgaben & Aufrufe
  4. Externe API-Aufrufe mocken
  5. Zeit und Zufall kontrollieren
  6. pytest-mock
  7. Typische Fallen
  8. Fazit

Guter Test-Code isoliert die Einheit, die er prüft. Sobald aber eine externe API, das Dateisystem, die Uhr oder ein Zufallsgenerator im Spiel ist, wird das schwierig — die Tests werden langsam, flaky oder abhängig von der Außenwelt. Mocking löst das.

Warum mocken?

Ein Test, der eine echte API ruft, ist kein Unit-Test mehr: Er ist langsam, bräuchte Netz und schlägt fehl, wenn der Dienst down ist. Mocking ersetzt solche Abhängigkeiten durch kontrollierte Attrappen.

Mocke die Grenzen deines Systems — externe Dienste, Zeit, Zufall — nicht deine eigene Logik. Was du mockst, testest du nicht mehr.

patch als Decorator & Context Manager

from unittest.mock import patch

# Als Decorator
@patch("myapp.services.send_email")
def test_registrierung(mock_send):
    register_user("e@example.com")
    mock_send.assert_called_once()

# Als Context Manager
def test_registrierung_cm():
    with patch("myapp.services.send_email") as mock_send:
        register_user("e@example.com")
        mock_send.assert_called_once()

Wichtig ist wo gepatcht wird: Immer dort, wo das Objekt benutzt wird, nicht wo es definiert ist. Das ist die häufigste Mocking-Falle.

# services.py
from emails import send_email   # importiert hierher

def register_user(email):
    send_email(email)

# RICHTIG: dort patchen, wo es benutzt wird
@patch("myapp.services.send_email")   # nicht "emails.send_email"!
def test_x(mock): ...

MagicMock: Rückgaben & Aufrufe prüfen

from unittest.mock import MagicMock

mock = MagicMock()
mock.get_user.return_value = {"id": 1, "name": "Eugen"}

result = mock.get_user(42)
assert result["name"] == "Eugen"

# Aufrufe inspizieren
mock.get_user.assert_called_once_with(42)
print(mock.get_user.call_args)      # welche Argumente?
print(mock.get_user.call_count)     # wie oft?

# Exception simulieren
mock.get_user.side_effect = ValueError("nicht gefunden")

Externe API-Aufrufe mocken

# services.py
import requests

def wetter_holen(stadt):
    r = requests.get(f"https://api.example.com/wetter/{stadt}")
    return r.json()["temperatur"]
from unittest.mock import patch, MagicMock

@patch("myapp.services.requests.get")
def test_wetter(mock_get):
    mock_get.return_value = MagicMock(
        status_code=200,
        json=lambda: {"temperatur": 22}
    )
    assert wetter_holen("Berlin") == 22
    mock_get.assert_called_once_with("https://api.example.com/wetter/Berlin")

Für requests speziell lohnt sich responses oder requests-mock — damit mockt man auf HTTP-Ebene statt die Bibliothek zu patchen.

Zeit und Zufall kontrollieren

from unittest.mock import patch
from datetime import datetime

@patch("myapp.services.datetime")
def test_mit_fixer_zeit(mock_dt):
    mock_dt.now.return_value = datetime(2026, 1, 1, 12, 0)
    assert ist_neujahr() is True

# Für datetime elegant: die Bibliothek freezegun
from freezegun import freeze_time

@freeze_time("2026-01-01")
def test_neujahr():
    assert ist_neujahr() is True

pytest-mock: der mocker-Fixture

# pip install pytest-mock
def test_registrierung(mocker):
    mock_send = mocker.patch("myapp.services.send_email")
    register_user("e@example.com")
    mock_send.assert_called_once()

# Kein Decorator-Stapel, keine with-Blöcke -> lesbarer bei mehreren Mocks

Typische Fallen

Fazit

Mocking ist ein Skalpell, kein Vorschlaghammer: Isoliere die Grenzen deines Systems — externe Dienste, Zeit, Zufall — und lass deine eigene Logik echt laufen. Wer sauber am richtigen Ort patcht und nicht zu viel mockt, bekommt schnelle, deterministische Tests, die trotzdem etwas aussagen.

Yevhen Chubchyk
Yevhen Chubchyk
Senior Python / Django Entwickler · Freelancer seit 2016 · 20+ Jahre IT-Erfahrung. Baut testgetriebene Backend-Systeme für Kunden im DACH-Raum.