Contract Testing für GraphQL APIs mit Mock Schemas
AI generated
{ }
type
GraphQL · Contract Testing · Mock Schema · CI/CD
Contract Testing für GraphQL APIs
mit Mock Schemas als ausführbarem Vertrag

Ein GraphQL-Schema ist bereits ein maschinenlesbarer Vertrag zwischen Frontend und Backend. Mit einem Mock Schema wird dieser Vertrag ausführbar: Frontend-Teams entwickeln gegen realistische Testdaten, lange bevor das Backend fertig ist, und Breaking Changes fallen automatisiert auf, statt erst in Production.

18 Min. Lesezeit addMocksToSchema · Faker · Schema-Diff · CI Node.js · Apollo · GraphQL Tools

1. Warum Contract Testing bei GraphQL anders funktioniert als bei REST

Bei REST-APIs braucht Contract Testing zusätzliche Werkzeuge wie Pact, weil kein maschinenlesbarer Vertrag zwischen Client und Server existiert, der über die Dokumentation hinausgeht. Bei GraphQL ist der Vertrag bereits Teil der Technologie: Das Schema selbst definiert präzise, welche Felder, Typen und Argumente existieren, und jede Query wird gegen genau dieses Schema validiert. Contract Testing für GraphQL APIs muss diesen bereits vorhandenen Vertrag also nicht neu erfinden, sondern nutzbar machen, bevor die eigentliche Implementierung fertig ist.

Der Denkfehler, dem viele Teams unterliegen: Sie verwechseln Schema-Validierung mit Contract Testing. Eine Query, die gegen das Schema valide ist, sagt nichts darüber aus, ob der Server tatsächlich sinnvolle Daten liefert, ob Paginierung korrekt funktioniert, oder ob ein Frontend mit realistischen Antwortformen umgehen kann. Genau diese Lücke schließt Contract Testing mit Mock Schemas: ein ausführbares Schema, das plausible Testdaten für jede Query liefert, ohne dass das echte Backend existieren muss.

2. Was ein Mock Schema als ausführbarer Vertrag leistet

Ein Mock Schema ist ein vollständig ausführbares GraphQL-Schema, bei dem jeder Resolver automatisch generierte oder gezielt konfigurierte Testdaten zurückgibt, statt eine echte Datenquelle anzusprechen. Der entscheidende Unterschied zu einer statischen JSON-Fixture: Ein Mock Schema beantwortet jede beliebige valide Query, inklusive Filtern, verschachtelten Feldern und Variablen, genau wie ein echter Server, nur eben mit generierten statt echten Daten.

Für Contract Testing bedeutet das: Ein Frontend-Team kann gegen das Mock Schema exakt dieselben Queries schreiben, die später gegen das echte Backend laufen, und bekommt strukturell identische Antworten. Ändert sich das Schema später inkompatibel, schlägt dieselbe Query sowohl gegen das Mock Schema als auch gegen das echte Backend fehl, was den Vertrag zwischen beiden Seiten konkret überprüfbar macht, statt ihn nur in einer README zu dokumentieren.

3. Mock Schemas mit @graphql-tools/mock aufsetzen

Das Paket @graphql-tools/mock ist der Standard, um aus einem bestehenden Schema, ob als SDL-Datei oder als Introspection-Ergebnis, automatisch ein vollständig ausführbares Mock Schema zu erzeugen. Die Funktion addMocksToSchema nimmt ein Schema entgegen und generiert für jeden Skalartyp plausible Standardwerte: Strings werden zu Lorem-Ipsum-Text, Booleans alternieren, IDs erhalten eindeutige generierte Werte.

Ohne weitere Konfiguration liefert dieses generische Mocking bereits valide, aber wenig aussagekräftige Antworten. Für ernsthaftes Contract Testing braucht es gezielte Mock-Resolver für die Felder, die tatsächlich fachlich relevant sind, etwa Preise, Lagerbestände oder Bestellstatus, während generische Felder wie interne IDs ruhig zufällig bleiben dürfen.


// mock-server.js — executable mock schema as a contract
const { makeExecutableSchema } = require('@graphql-tools/schema');
const { addMocksToSchema } = require('@graphql-tools/mock');
const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');
const fs = require('fs');

const typeDefs = fs.readFileSync('./schema.graphql', 'utf-8');
const schema = makeExecutableSchema({ typeDefs });

const mockedSchema = addMocksToSchema({
  schema,
  mocks: {
    // Generic scalar mocks apply everywhere unless overridden per field
    ID: () => Math.random().toString(36).slice(2, 10),
  },
});

const server = new ApolloServer({ schema: mockedSchema });
startStandaloneServer(server, { listen: { port: 4001 } });

4. Realistische Testdaten: Custom Mock Resolver und Faker

Generische Mocks reichen für einen ersten Smoke Test, scheitern aber, sobald ein Frontend fachlich plausible Werte braucht, etwa einen realistischen Preis statt einer zufälligen Fließkommazahl mit zwanzig Nachkommastellen. Der resolvers-Block von addMocksToSchema erlaubt es, für jeden Typ gezielt eine Faker-basierte Generierungsfunktion zu hinterlegen, die auf konkrete Felder zugeschnitten ist.

Ein realistisches Mock Schema für einen Produktkatalog generiert Preise in einem plausiblen Bereich, Produktnamen aus einem Warenkategorie-Vokabular statt aus generischem Lorem Ipsum, und Lagerbestände, die auch mal null sind, damit das Frontend den Fall "nicht vorrätig" testen kann, ohne auf einen echten Datensatz mit diesem Zustand warten zu müssen.


// mock-resolvers.js — domain-realistic data instead of generic lorem ipsum
const { faker } = require('@faker-js/faker');

const mocks = {
  Product: () => ({
    name: faker.commerce.productName(),
    price: Number(faker.commerce.price({ min: 5, max: 500 })),
    // ~10% of mocked products are deliberately out of stock
    inStock: faker.number.int({ min: 0, max: 10 }) > 0,
  }),
  Query: () => ({
    products: () => Array.from({ length: 12 }, () => ({})),
  }),
};

module.exports = { mocks };

5. Frontend-Entwicklung parallel zum Backend

Der praktische Hauptnutzen von Mock Schemas liegt in der Entkopplung von Frontend- und Backend-Fortschritt. Sobald ein Schema als SDL-Entwurf vorliegt, auch wenn noch kein einziger Resolver produktiv implementiert ist, kann das Frontend-Team gegen ein Mock Schema entwickeln, Komponenten bauen und sogar automatisierte Tests schreiben. Das Backend-Team implementiert parallel die echten Resolver gegen dasselbe Schema.

Dieses Modell funktioniert als Contract Testing, weil beide Teams gegen denselben Vertrag arbeiten: das Schema. Divergiert die Backend-Implementierung vom vereinbarten Schema, etwa weil ein Feld doch nullable sein muss, wird das beim nächsten Schema-Sync sofort sichtbar, weit bevor Frontend und Backend zum ersten Mal gegeneinander getestet werden, was in klassischen Integrationstests oft erst kurz vor dem Release passiert.

6. Konsumenten-Verträge prüfen: welche Felder der Client wirklich nutzt

Ein oft übersehener Teil von Contract Testing für GraphQL APIs ist die Frage, welche Felder eines Schemas überhaupt von echten Clients angefragt werden. Ein Backend-Team, das ein Feld entfernen will, muss wissen, ob irgendein Consumer, Web-Frontend, Mobile-App oder Drittanbieter-Integration, dieses Feld tatsächlich verwendet, statt sich auf Vermutungen zu verlassen.

GraphQL Inspector und ähnliche Tools bieten dafür Operation-Coverage-Reports: Alle bekannten Client-Queries werden gesammelt, meist aus den .graphql-Dateien der jeweiligen Frontend-Repositories, und gegen das Schema abgeglichen. Das Ergebnis ist eine Liste ungenutzter Felder, die gefahrlos entfernt werden können, und genutzter Felder, deren Entfernung einen konkreten, benannten Consumer bricht.

7. Mock Schema und echtes Schema synchron halten

Das größte Risiko bei Contract Testing mit Mock Schemas ist Drift: Das Mock Schema wird einmal aus dem echten Schema generiert und danach unabhängig weiterentwickelt, während das echte Backend-Schema sich in eine andere Richtung verändert. Ohne Gegenmaßnahme verliert das Mock Schema nach wenigen Wochen seine Aussagekraft als Vertrag, weil es nicht mehr dasselbe beschreibt wie die Produktion.

Die zuverlässige Lösung ist, das Mock Schema niemals manuell zu pflegen, sondern bei jedem CI-Lauf frisch aus dem aktuellen SDL-Schema oder einer aktuellen Introspection zu generieren. Ergänzend prüft ein Schema-Diff-Tool wie GraphQL Inspector bei jedem Pull Request, ob die vorgenommene Änderung ein Breaking Change ist, und blockiert den Merge, falls ein als genutzt markiertes Feld entfernt oder inkompatibel verändert wird.


# .github/workflows/contract-check.yml
name: GraphQL Contract Check
on: [pull_request]
jobs:
  schema-diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      # Compares the new schema against main and fails on breaking changes
      - run: npx graphql-inspector diff schema-main.graphql schema.graphql --fail-on-breaking

8. Standalone Mock-Server: GraphQL Faker und Prism im Vergleich

Neben der programmatischen Integration über @graphql-tools/mock gibt es eigenständige Mock-Server, die ohne eigenen Code-Aufwand ein Schema als HTTP-Endpoint bereitstellen. GraphQL Faker startet direkt aus einer SDL-Datei einen laufenden GraphQL-Server mit Faker-basierten Mock-Daten und einem GraphiQL-Explorer, ideal für schnelle Demos oder wenn kein eigenes Node.js-Projekt für den Mock-Server aufgesetzt werden soll.

Prism, ursprünglich für OpenAPI entwickelt, unterstützt inzwischen ebenfalls GraphQL-Mocking und punktet vor allem in Teams, die bereits REST- und GraphQL-APIs parallel betreiben und ein einheitliches Mocking-Tool für beide Vertragstypen bevorzugen. Für reine GraphQL-Projekte bleibt @graphql-tools/mock jedoch die flexiblere Wahl, weil sich Custom-Mock-Resolver direkt in JavaScript oder TypeScript definieren lassen, statt über eine separate Konfigurationssprache.

9. Contract-Testing-Strategien im Vergleich

Je nach Teamgröße und Reifegrad des Schemas eignen sich unterschiedliche Strategien für Contract Testing bei GraphQL APIs.

Strategie Nutzt Stärke Einschränkung
Generisches Mocking addMocksToSchema ohne Custom Resolver In Minuten startklar Daten fachlich wenig aussagekräftig
Faker-basiertes Mocking Custom Resolver + @faker-js/faker Realistische, testbare Randfälle Pflegeaufwand pro Domänentyp
Operation-Coverage-Analyse GraphQL Inspector gegen Client-Queries Zeigt tatsächlich genutzte Felder Benötigt Zugriff auf alle Consumer-Repos
Schema-Diff in CI graphql-inspector diff --fail-on-breaking Verhindert Breaking Changes vor Merge Erkennt keine semantischen Datenfehler

In der Praxis kombinieren reife GraphQL-Teams alle vier Strategien: generisches Mocking für schnelle Prototypen, Faker-basiertes Mocking für ernsthafte Frontend-Entwicklung, Operation-Coverage für sichere Deprecations und Schema-Diff in CI als letzte, automatisierte Verteidigungslinie gegen unbeabsichtigte Breaking Changes.

Mironsoft

GraphQL-Contract-Testing, Mock Schemas und CI-Pipelines

Frontend und Backend parallel entwickeln, ohne Überraschungen?

Wir bauen Mock Schemas mit realistischen Testdaten, richten Operation-Coverage-Reports ein und integrieren Schema-Diff-Checks in eure CI-Pipeline, damit Breaking Changes vor dem Merge auffallen, nicht danach.

Mock-Schema-Setup

addMocksToSchema mit domänenspezifischen Faker-Resolvern konfigurieren

Coverage-Reports

Genutzte Felder über alle Consumer-Repositories hinweg sichtbar machen

CI-Schema-Diff

Breaking-Change-Erkennung als verbindliches Pull-Request-Gate

10. Zusammenfassung

Contract Testing für GraphQL APIs mit Mock Schemas nutzt die Tatsache, dass GraphQL bereits einen maschinenlesbaren Vertrag mitbringt, das Schema selbst. Ein mit addMocksToSchema und Faker-basierten Resolvern angereichertes Mock Schema macht diesen Vertrag ausführbar, lange bevor die echte Implementierung steht, und erlaubt Frontend- und Backend-Teams, unabhängig voneinander gegen denselben Vertrag zu arbeiten.

Der Vertrag bleibt nur so lange verlässlich, wie er automatisiert geprüft wird: Operation-Coverage-Reports zeigen, welche Felder echte Consumer nutzen, und Schema-Diff-Checks in der CI-Pipeline verhindern, dass Breaking Changes unbemerkt den main-Branch erreichen. Zusammen ersetzen diese Bausteine aufwendige, manuell koordinierte Integrationstests durch automatisiertes, jederzeit wiederholbares Contract Testing.

Contract Testing für GraphQL APIs — Das Wichtigste auf einen Blick

Schema als Vertrag

GraphQL bringt den Vertrag bereits mit, das Schema selbst. Mock Schemas machen ihn ausführbar.

Realistische Testdaten

addMocksToSchema plus Faker-Resolver statt generischem Lorem Ipsum für aussagekräftige Tests.

Coverage statt Vermutung

Operation-Coverage-Reports zeigen, welche Felder echte Consumer tatsächlich anfragen.

Automatisierte Absicherung

Schema-Diff-Checks in CI verhindern Breaking Changes vor dem Merge, nicht danach.

11. FAQ: Contract Testing für GraphQL APIs

1Was ist Contract Testing bei GraphQL?
Automatisierte Prüfung, ob Frontend und Backend denselben Schema-Vertrag einhalten, ausführbar über Mock Schemas.
2Was ist ein Mock Schema?
Ein ausführbares Schema mit generierten statt echten Daten, das jede valide Query wie ein echter Server beantwortet.
3Wie erstelle ich ein Mock Schema?
Mit addMocksToSchema aus @graphql-tools/mock, angewendet auf ein bestehendes SDL-Schema.
4Warum reichen generische Mocks nicht aus?
Sie sind fachlich wenig aussagekräftig. Faker-basierte Custom Resolver liefern realistische Werte und Randfälle.
5Wie hilft ein Mock Schema bei paralleler Entwicklung?
Frontend entwickelt gegen das Mock Schema, während Backend die echten Resolver implementiert, beide gegen denselben Vertrag.
6Was ist Operation Coverage?
Abgleich zwischen Schema und tatsächlich genutzten Client-Queries, zeigt sicher entfernbare Felder.
7Wie vermeide ich Schema-Drift?
Mock Schema nie manuell pflegen, sondern bei jedem CI-Lauf frisch aus dem aktuellen Schema generieren.
8Was macht GraphQL Inspector?
Vergleicht Schema-Versionen auf Breaking Changes und erstellt Operation-Coverage-Reports.
9GraphQL Faker vs. Prism?
GraphQL Faker ist rein GraphQL-fokussiert, Prism unterstützt zusätzlich OpenAPI für gemischte Stacks.
10Wie integriere ich Schema-Diff in CI?
Mit graphql-inspector diff --fail-on-breaking als CI-Schritt, der bei Breaking Changes den Build stoppt.