Zum Inhalt springen
Tooling

Testdaten in CI-Pipelines: Strategien jenseits von Fixtures

9 min Lesezeit
Testing CI/CD Testdaten

Jedes Projekt, das länger als drei Monate lebt, hat ein Testdatenproblem. Am Anfang reichen ein paar JSON-Fixtures. Dann kommen Beziehungen zwischen Entitäten dazu, dann Migrationen, dann Edge Cases. Irgendwann verbringt das Team mehr Zeit mit der Pflege von Testdaten als mit dem Schreiben von Tests.

Das Problem mit statischen Fixtures

Fixtures — also hartcodierte Testdaten in JSON- oder YAML-Dateien — haben einen fundamentalen Nachteil: Sie sind gekoppelt an ein bestimmtes Schema. Jede Datenbankmigraton erfordert ein Update aller Fixtures. Bei zehn Tabellen mit je drei Fixture-Dateien sind das 30 Dateien, die synchron gehalten werden müssen.

Strategie 1: Factories

Factories erzeugen Testdaten programmatisch. Statt den Zustand zu beschreiben, beschreiben sie den Prozess.

Factory-Pattern mit Builder typescript
class UserFactory {
  private overrides: Partial<User> = {};

  withRole(role: UserRole): this {
    this.overrides.role = role;
    return this;
  }

  withOrders(count: number): this {
    this.overrides._orders = count;
    return this;
  }

  build(): User {
    return {
      id: randomUUID(),
      email: `test-${randomUUID().slice(0, 8)}@example.com`,
      role: 'user',
      createdAt: new Date(),
      ...this.overrides,
    };
  }
}

// Nutzung im Test
const admin = new UserFactory().withRole('admin').build();
const customerWithHistory = new UserFactory()
  .withRole('customer')
  .withOrders(5)
  .build();

Der Vorteil: Wenn sich das Schema ändert, änderst du die Factory — nicht 30 Fixture-Dateien. Und der Testcode dokumentiert die Intention: “Ein Admin” oder “Ein Kunde mit Bestellhistorie”.

Strategie 2: Database Snapshots

Für Integrationstests, die eine realistische Datenmenge brauchen, sind Snapshots oft die pragmatischste Lösung.

Snapshot-basierter Test-Workflow bash
# Snapshot erstellen (einmalig oder in CI)
pg_dump --format=custom \
  --exclude-table-data='audit_log' \
  --exclude-table-data='sessions' \
  testdb > fixtures/baseline.dump

# Vor jedem Testlauf wiederherstellen
pg_restore --clean --if-exists \
  --dbname=testdb fixtures/baseline.dump

Strategie 3: Synthetische Daten

Für Tests, die realistische Datenverteilungen brauchen — etwa Performance-Tests oder ML-Pipelines — reichen weder Factories noch Snapshots. Hier kommen synthetische Daten ins Spiel.

Der Schlüssel ist, die statistischen Eigenschaften der Produktionsdaten zu reproduzieren, ohne die eigentlichen Daten zu kopieren. Das löst gleichzeitig das DSGVO-Problem: Synthetische Daten sind keine personenbezogenen Daten.

Die Pipeline: Alles zusammen

In der Praxis kombiniert man die Strategien:

TesttypStrategieBegründung
Unit TestsFactoriesSchnell, isoliert, schema-unabhängig
Integration TestsSnapshots + FactoriesRealistische Basis, gezielte Erweiterung
Performance TestsSynthetische DatenGroße Mengen, realistische Verteilung
E2E TestsSnapshotsKonsistenter, bekannter Zustand

Testdaten in CI: Praktische Hinweise

  1. Testdaten gehören in die Versionskontrolle. Snapshots als Artefakte, Factory-Definitionen als Code.
  2. Jeder Testlauf startet mit einem definierten Zustand. Keine Abhängigkeiten zwischen Tests.
  3. Datenbankmigrationen testen. Ein Snapshot von vor drei Monaten + alle Migrationen = aktuelle Schema-Validierung.
  4. Datenvolumen variieren. Was mit 10 Datensätzen funktioniert, kann mit 10.000 scheitern.

Fazit

Testdatenmanagement ist kein glamouröses Thema. Aber es ist eines, das über die Zuverlässigkeit einer CI-Pipeline entscheidet. Die Investition in eine durchdachte Strategie zahlt sich in jeder Pipeline-Minute zurück, die nicht mit flaky Tests verschwendet wird.