← Zurück zum Blog
TestingDjango21. Mai 2026· 12 min Lesezeit

Fixtures & Factory Boy: Testdaten sauber aufbauen

Inhalt
  1. Das Testdaten-Problem
  2. pytest-Fixtures
  3. Fixture-Scopes
  4. Factory Boy
  5. Relationen & SubFactory
  6. Traits & Sequenzen
  7. Fazit

Ein häufiger Grund, warum Testsuiten unwartbar werden: handgeschriebene Testdaten, die in jedem Test wiederholt und bei jeder Model-Änderung angefasst werden müssen. pytest-Fixtures und Factory Boy lösen das elegant.

Das Testdaten-Problem

# Mühsam und fehleranfällig - in jedem Test wiederholt
def test_etwas():
    user = User.objects.create_user("u1", "u1@x.de", "pw")
    cat = Category.objects.create(name="Tech")
    article = Article.objects.create(
        title="T", author=user, category=cat, status="published"
    )
    # ... eigentlicher Test erst hier

pytest-Fixtures: wiederverwendbare Bausteine

# conftest.py
import pytest
from django.contrib.auth import get_user_model

@pytest.fixture
def user(db):
    return get_user_model().objects.create_user("tester", password="pw")

@pytest.fixture
def category(db):
    return Category.objects.create(name="Tech")

# Fixtures können aufeinander aufbauen
@pytest.fixture
def article(db, user, category):
    return Article.objects.create(
        title="Test", author=user, category=category, status="published"
    )
# Test bekommt Fixtures per Parameter - sauber und lesbar
def test_artikel_sichtbar(client, article):
    response = client.get(f"/articles/{article.slug}/")
    assert response.status_code == 200

Fixture-Scopes: einmal vs. pro Test

Fixtures können unterschiedlich lange leben — das spart Zeit bei teuren Aufbauten:

@pytest.fixture(scope="function")  # Standard: pro Test neu
def frischer_user(db): ...

@pytest.fixture(scope="session")   # einmal für den ganzen Lauf
def api_config(): return load_config()

@pytest.fixture(scope="module")    # einmal pro Testdatei
def teure_ressource(): ...

Factory Boy: Testdaten als Fabriken

Factory Boy erzeugt Objekte mit sinnvollen Defaults — du gibst nur an, was für den Test wirklich relevant ist:

# factories.py
import factory
from factory.django import DjangoModelFactory

class UserFactory(DjangoModelFactory):
    class Meta:
        model = "auth.User"
    username = factory.Sequence(lambda n: f"user_{n}")
    email = factory.LazyAttribute(lambda o: f"{o.username}@example.com")

class ArticleFactory(DjangoModelFactory):
    class Meta:
        model = Article
    title = factory.Faker("sentence", locale="de_DE")
    status = "draft"
# Im Test: nur das Relevante angeben, Rest kommt automatisch
def test_veroeffentlicht(db):
    a = ArticleFactory(status="published")   # title etc. automatisch
    assert a.status == "published"

# Mehrere auf einmal
def test_liste(db):
    ArticleFactory.create_batch(5, status="published")
    assert Article.objects.filter(status="published").count() == 5

Relationen & SubFactory

class ArticleFactory(DjangoModelFactory):
    class Meta:
        model = Article
    title = factory.Faker("sentence")
    # Verknüpfte Objekte automatisch miterzeugen:
    author = factory.SubFactory(UserFactory)
    category = factory.SubFactory(CategoryFactory)

# ArticleFactory() erzeugt jetzt automatisch User + Category mit

Traits & Sequenzen

Traits bündeln Varianten, Sequenzen sorgen für eindeutige Werte:

class ArticleFactory(DjangoModelFactory):
    class Meta:
        model = Article
    title = factory.Sequence(lambda n: f"Artikel {n}")
    status = "draft"

    class Params:
        veroeffentlicht = factory.Trait(
            status="published",
            published_at=factory.LazyFunction(timezone.now),
        )

# Nutzung:
ArticleFactory(veroeffentlicht=True)  # setzt status + published_at

Fazit

Gute Testdaten sind wiederverwendbar und sprechend. pytest-Fixtures kapseln den Aufbau, Factory Boy liefert sinnvolle Defaults und macht klar, was ein Test wirklich braucht. Zusammen ergeben sie Tests, die man auch in einem Jahr noch versteht — und die eine Model-Änderung nicht reihenweise brechen lässt.

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.