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

API-Tests mit Django REST Framework & pytest

Inhalt
  1. Der APIClient
  2. CRUD-Endpunkte testen
  3. Authentifizierung
  4. Permissions prüfen
  5. Serializer-Validierung
  6. Fixtures für API-Tests
  7. Fazit

REST-APIs sind Verträge: Clients verlassen sich auf Statuscodes, Feldnamen und Verhalten. Genau deshalb gehören sie umfassend getestet. Mit DRF und pytest geht das erstaunlich elegant — hier die Muster, die ich in jedem API-Projekt nutze.

Der APIClient

DRF bringt einen eigenen Test-Client mit, der JSON und Authentifizierung sauber unterstützt:

# conftest.py
import pytest
from rest_framework.test import APIClient

@pytest.fixture
def api():
    return APIClient()

@pytest.fixture
def auth_api(api, user):
    api.force_authenticate(user=user)
    return api

CRUD-Endpunkte testen

@pytest.mark.django_db
class TestArticleAPI:
    def test_liste(self, api):
        ArticleFactory.create_batch(3, status="published")
        response = api.get("/api/articles/")
        assert response.status_code == 200
        assert len(response.data["results"]) == 3

    def test_detail(self, api):
        article = ArticleFactory(status="published")
        response = api.get(f"/api/articles/{article.id}/")
        assert response.status_code == 200
        assert response.data["title"] == article.title

    def test_erstellen(self, auth_api):
        payload = {"title": "Neu", "status": "draft"}
        response = auth_api.post("/api/articles/", payload, format="json")
        assert response.status_code == 201
        assert Article.objects.filter(title="Neu").exists()

Authentifizierung

@pytest.mark.django_db
def test_erstellen_ohne_auth_verboten(api):
    response = api.post("/api/articles/", {"title": "X"}, format="json")
    assert response.status_code == 401  # nicht authentifiziert

@pytest.mark.django_db
def test_token_auth(api, user):
    from rest_framework.authtoken.models import Token
    token = Token.objects.create(user=user)
    api.credentials(HTTP_AUTHORIZATION=f"Token {token.key}")
    response = api.get("/api/articles/")
    assert response.status_code == 200

Permissions prüfen

Ein häufig übersehener Testfall: Darf ein Nutzer nur seine eigenen Objekte ändern?

@pytest.mark.django_db
def test_fremden_artikel_nicht_aendern(api):
    autor_a = UserFactory()
    autor_b = UserFactory()
    artikel = ArticleFactory(author=autor_a)

    api.force_authenticate(user=autor_b)   # anderer Nutzer
    response = api.patch(f"/api/articles/{artikel.id}/",
                         {"title": "gekapert"}, format="json")
    assert response.status_code == 403   # verboten

Serializer-Validierung

@pytest.mark.django_db
def test_ungueltige_daten(auth_api):
    # title fehlt (Pflichtfeld)
    response = auth_api.post("/api/articles/", {"status": "draft"}, format="json")
    assert response.status_code == 400
    assert "title" in response.data

@pytest.mark.django_db
def test_ungueltiger_status(auth_api):
    response = auth_api.post("/api/articles/",
        {"title": "X", "status": "quatsch"}, format="json")
    assert response.status_code == 400
    assert "status" in response.data

Fixtures für API-Tests

Wiederkehrende Setups bündele ich in Fixtures, damit die Tests schlank bleiben:

@pytest.fixture
def veroeffentlichte_artikel(db):
    return ArticleFactory.create_batch(5, status="published")

@pytest.fixture
def admin_api(api):
    admin = UserFactory(is_staff=True, is_superuser=True)
    api.force_authenticate(user=admin)
    return api

# Test bleibt lesbar:
def test_admin_sieht_entwuerfe(admin_api, veroeffentlichte_artikel):
    ArticleFactory(status="draft")
    response = admin_api.get("/api/articles/?status=draft")
    assert len(response.data["results"]) == 1

Fazit

Gute API-Tests decken mehr ab als "gibt 200 zurück": Statuscodes, Auth, Permissions (besonders Fremd-Zugriff!), Validierung und Randfälle. Mit DRFs APIClient, pytest-Fixtures und Factory Boy bleiben sie dabei schlank und lesbar. So wird die API zum verlässlichen Vertrag — auch nach dem nächsten Refactoring.

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.