testdatatools
Praktische Entscheidungshilfe

PostgreSQL-Datenbank für Tests maskieren und das Ergebnis prüfen

Ein kleiner Prüffall mit zwei Kunden und drei Bestellungen. Maskierung, Dump, Restore und eine absichtlich verletzte fachliche Erwartung.

Redaktionell geprüft: · Quellen und Geltungsbereich unten

Prüfstatus vom 4. November 2026. Dieses SQL-Beispiel ist redaktionell geprüft, aber noch nicht in PostgreSQL ausgeführt. Die Kommentare nennen erwartete Ergebnisse.

Der Kunde hat bezahlt. In der Testumgebung fehlen seine Bestellungen. Bevor wir weitere Maskierungsregeln bauen, reduzieren wir den Fehler auf zwei Tabellen und drei Bestellungen.

Das ist die vereinfachte Fortsetzung des konstruierten Beispiels aus dem Masking-Ratgeber. Hier verbindet ein deklarierter Fremdschlüssel Kunden und Bestellungen innerhalb einer PostgreSQL-Datenbank. Die zusätzliche Verknüpfung zwischen zwei Services aus dem Ratgeber wäre ein eigener Integrationstest.

Wir ersetzen Namen und E-Mails, entfernen Notizen und prüfen den exportierten und wiederhergestellten Bestand. Anschließend verändern wir absichtlich einen Bestellstatus. Damit lässt sich zeigen, ob unsere Prüfung den Fehler bemerkt, obwohl weiterhin alle Fremdschlüssel gültig sind.

Was soll nach der Maskierung noch funktionieren?

Wir verwenden zwei Kunden und drei Bestellungen. Kunde 1 hat zwei bezahlte Bestellungen über 10.000 und 20.000 Cent. Kunde 2 hat eine offene Bestellung über 5.000 Cent.

Nach der Transformation erwarten wir weiterhin zwei Kunden, drei Bestellungen, keine verwaisten Beziehungen und eine bezahlte Summe von 30.000 Cent für Kunde 1. Namen, E-Mails und Notizen folgen den unten festgelegten Ersatzregeln.

Die Beispieldaten anlegen

Lege auf einer isolierten PostgreSQL-Testinstanz eine neue Datenbank masking_demo an. Führe den folgenden Code dort aus. Die Tabelle enthält ausschließlich die Felder, die dieser kleine Test benötigt.

CREATE TABLE customers (
    customer_id integer PRIMARY KEY,
    name text NOT NULL,
    email text NOT NULL UNIQUE,
    internal_note text
);

CREATE TABLE orders (
    order_id integer PRIMARY KEY,
    customer_id integer NOT NULL REFERENCES customers(customer_id),
    status text NOT NULL,
    amount_cents integer NOT NULL
);

INSERT INTO customers VALUES
    (1, 'Demo Person A', 'original-a@example.invalid', 'Erfundene Notiz A'),
    (2, 'Demo Person B', 'original-b@example.invalid', 'Erfundene Notiz B');

INSERT INTO orders VALUES
    (101, 1, 'paid', 10000),
    (102, 1, 'paid', 20000),
    (103, 2, 'pending', 5000);

Die nicht benötigten Werte ersetzen

Für diese Fixture reichen eindeutige, aus der Kunden-ID abgeleitete Ersatzwerte. Die Bestellungen und IDs bleiben erhalten, damit wir die Join-Beziehung prüfen können.

BEGIN;

UPDATE customers
SET name = 'Testkunde ' || customer_id,
    email = 'customer-' || customer_id || '@example.invalid',
    internal_note = NULL;

COMMIT;

Diese einfache Regel ist speziell auf die zwei erfundenen Kunden zugeschnitten. Bei einer realen Quelle müssen bestehende Ersatzwerte, zusätzliche Constraints und weitere identifizierende Felder berücksichtigt werden. Insbesondere bleiben ursprüngliche IDs und Bestellinformationen hier erhalten. Das ist eine bewusste Eigenschaft dieser Demonstration und muss für einen echten Datensatz gesondert bewertet werden.

Die maskierte Kopie exportieren und wiederherstellen

Verwende passend konfigurierte PostgreSQL-Verbindungen und eine neue, leere Zieldatenbank masking_demo_restored auf derselben isolierten Testinstanz. Die folgenden Befehle verwenden die normalen lokalen Verbindungseinstellungen. Server, Clientversionen und Verbindungsparameter gehören ins spätere Laufprotokoll.

pg_dump --format=custom --no-owner --no-acl \
  --dbname=masking_demo --file=masking_demo.dump

createdb masking_demo_restored

pg_restore --exit-on-error --single-transaction \
  --no-owner --no-acl \
  --dbname=masking_demo_restored masking_demo.dump

Das Custom-Archiv wird mit pg_restore eingespielt. Der Restore bricht bei einem Fehler ab und läuft hier in einer Transaktion. Verwende für diesen Ablauf eine kompatible Kombination aus Server und PostgreSQL-Clientwerkzeugen. [3]

Die wiederhergestellte Datenbank prüfen

Führe die folgenden Abfragen gegen masking_demo_restored aus. Die Sollwerte sind vorab festgelegte Abnahmekriterien dieses Beispiels.

SELECT count(*) AS customer_count FROM customers;
-- Erwartet: 2

SELECT count(*) AS order_count FROM orders;
-- Erwartet: 3

SELECT count(*) AS orphan_orders
FROM orders o
LEFT JOIN customers c ON c.customer_id = o.customer_id
WHERE c.customer_id IS NULL;
-- Erwartet: 0

SELECT count(*) AS unexpected_customer_values
FROM customers
WHERE name IS DISTINCT FROM ('Testkunde ' || customer_id)
   OR email IS DISTINCT FROM ('customer-' || customer_id || '@example.invalid')
   OR internal_note IS NOT NULL;
-- Erwartet: 0

SELECT customer_id, count(*) AS paid_orders,
       sum(amount_cents) AS total_cents
FROM orders
WHERE status = 'paid'
GROUP BY customer_id
ORDER BY customer_id;
-- Erwartet: genau eine Zeile mit 1 | 2 | 30000

Die Prüfung des fachlichen Ergebnisses ist wesentlich. Ein Datensatz kann gültige Fremdschlüssel enthalten und trotzdem falsche Statuswerte oder Beträge liefern. Für diese Fixture solltest du deshalb auch die drei Bestellzeilen mit der festgelegten Ausgangsliste vergleichen.

Den Prüfungen einen Fehler geben

Ein Test ist erst dann überzeugend, wenn du auch sein Fehlverhalten kennst. Ändere im wiederhergestellten Demo-Ziel vorübergehend den Status einer bezahlten Bestellung und führe die fachliche Abfrage erneut aus.

BEGIN;
UPDATE orders SET status = 'pending' WHERE order_id = 102;

SELECT customer_id, count(*) AS paid_orders,
       sum(amount_cents) AS total_cents
FROM orders
WHERE status = 'paid'
GROUP BY customer_id
ORDER BY customer_id;
-- Erwarteter Fehlerfall: 1 | 1 | 10000
-- Das verletzt das ursprüngliche Soll 1 | 2 | 30000.

ROLLBACK;

Die Anzahl der Datensätze und sämtliche Fremdschlüssel bleiben dabei erhalten. Die fachliche Prüfung muss trotzdem fehlschlagen. Nach dem Rollback sollte sie wieder genau 1 | 2 | 30000 liefern. Die aufgeführten Ergebnisse sind hergeleitete Sollwerte. Ein protokollierter PostgreSQL-Lauf durch diese Redaktion steht noch aus.

Wenn derselbe Kunde zusätzlich in einem zweiten System vorkommt, ergänze eine eigene Prüfung für diese Verbindung. Die lokale Fremdschlüsselabfrage kann sie nicht erfassen.

Wie wird daraus ein Verfahren für größere Datenbanken?

Bei einer größeren Quelle müssen Auswahl, Transformation und Prüfung wiederholbar beschrieben werden. Prüfe vor einer Toolentscheidung insbesondere zusammengesetzte Schlüssel, zirkuläre Beziehungen, JSON, Freitext und Verknüpfungen über mehrere Datenbanken hinweg. Vereinbare außerdem, wie ein fehlgeschlagener Lauf erkannt und eine unvollständige Kopie zurückgehalten wird.

Greenmask dokumentiert einen PostgreSQL-Workflow für Transformationen und Dumps. Jailer beschreibt relationale Extraktion anhand eines Modells. Der Vergleich Jailer vs Greenmask hilft bei der Entscheidung zwischen diesen Abläufen. Wer mehrere Datenbanken, zentrale Berechtigungen oder gemeinsam gepflegte Regeln benötigt, kann über die Vergleichszentrale weitere Kandidaten anhand dieser Anforderungen auswählen. [4]

Was gehört ins Prüfprotokoll?

Notiere Datenbank- und Werkzeugversion, verwendete Dateien, Sollwerte, tatsächliche Ergebnisse und notwendige manuelle Schritte. Wiederhole die Abfragen im wiederhergestellten Ziel. Ergänze für reale Datenquellen eine Prüfung der verbleibenden sensiblen Inhalte und des gesamten Bereitstellungswegs.

Die Beispielabfragen zeigen dir, ob die vereinbarten Transformationsregeln und der kleine fachliche Test funktionieren. Für einen produktiven Workflow erweitere sie um die Eigenschaften, von denen deine Anwendung tatsächlich abhängt.

Quellen zum Artikel

  1. PostgreSQL — pg_dump, PostgreSQL — pg_restore.
  2. Greenmask — Dokumentation, Jailer vs Greenmask — dokumentierte Produktgrenzen.

So prüfen wir Quellen

Wähle den nächsten Schritt