Inhaltsverzeichnis17 Abschnitte
- Schnellvergleich
- dbt-Tests
- Eingebaute generic Tests
- Custom Singular Tests
- Great Expectations
- Soda Core
- pytest für Datenpipelines
- Layern: alle vier zusammen
- Häufige Pitfalls
- FAQ
- Wenn ich nur ein Tool wählen darf — welches?
- Kann ich dbt-Tests und Soda parallel betreiben?
- Wie verhindere ich, dass Tests zur Wartungslast werden?
- Sind Data-Quality-Tools DSGVO-relevant?
- Reicht Soda Cloud oder brauche ich GX?
- Wrap-up
- Weiterlesen
TL;DR: dbt-Tests für SQL-Model-Output, pytest für Python-Transform-Logik, Soda Core für Pipeline-Gates (Freshness, Cross-Tabellen), Great Expectations für Profiling und Quality-Reports. Kein Tool deckt alle vier Layer ab — versuch das nicht.
Eine schlechte Zeile in einer Faktentabelle kostet mehr als die Engineering-Stunden, sie abzufangen. Sie kostet das Vertrauen jedes Analysten, der darauf einen Report gebaut hat.
Data-Testing-Frameworks existieren, um Datenqualitätsprobleme zu fangen, bevor sie Downstream-Konsumenten erreichen. Vier Tools dominieren den Bereich: dbt-Tests, Great Expectations, Soda Core und pytest. Sie überlappen sich im Zweck, unterscheiden sich aber deutlich in Philosophie, Integrationsfläche und operativer Komplexität.
Schnellvergleich
| dbt-Tests | Great Expectations | Soda Core | pytest | |
|---|---|---|---|---|
| Hauptzweck | SQL-Model-Validierung | Dataset-Profiling & Expectations | Pipeline-Level-Quality-Checks | Unit-Tests von Python-Logik |
| Konfiguration | YAML | Python / JSON | YAML (SodaCL) | Python |
| Läuft in | dbt-Pipeline | Standalone oder Airflow | Standalone oder Airflow | CI/CD, lokale Dev |
| Lernkurve | Niedrig | Hoch | Mittel | Niedrig (mit Python-Kenntnissen) |
| Reporting-UI | dbt docs | Data Docs (self-hosted) | Soda Cloud (SaaS) | Console / custom |
| Best fit | dbt-native Teams | Komplexe Profiling-Needs | Cross-Platform-Quality-Gates | Transformation-Code testen |
| Open Source | Ja | Ja | Ja (Core) | Ja |
dbt-Tests
dbt hat ein natives Testing-Framework in die CLI eingebaut. Tests werden in .yml-Files neben deinen Models definiert und mit dbt test ausgeführt.
Eingebaute generic Tests
# models/schema.yml
models:
- name: dim_customer
columns:
- name: customer_sk
tests:
- unique
- not_null
- name: country_code
tests:
- not_null
- accepted_values:
values: ['DE', 'FR', 'US', 'GB', 'NL']
- name: customer_id
tests:
- relationships:
to: ref('stg_customers')
field: customer_id
Diese vier eingebauten Tests (unique, not_null, accepted_values, relationships) decken den Großteil dessen ab, was die meisten Teams brauchen.
Custom Singular Tests
Für Logik, die nicht in Generic Tests passt, schreib einen Singular Test — eine SQL-Query, die nur dann Zeilen zurückgibt, wenn etwas falsch ist:
-- tests/assert_no_negative_revenue.sql
-- Fails (returns rows) if any order has negative revenue
SELECT
order_id,
revenue
FROM {{ ref('fct_orders') }}
WHERE revenue < 0
Gibt diese Query Zeilen zurück, markiert dbt test sie als failed. Einfach, versioniert und neben dem Model, das er schützt.
Wann dbt-Tests nutzen: Du nutzt schon dbt. Tests sind die richtige erste Verteidigungslinie für SQL-Model-Output-Validierung. Starte hier.
Great Expectations
Great Expectations (GX) ist die mächtigste Option, aber auch die komplexeste im Setup. Das Kernkonzept ist eine Expectation Suite — eine Sammlung von Assertions über ein Dataset, die du einmal definierst und wiederholt laufen lässt.
# Python: Great Expectations core v1 (simplified)
import great_expectations as gx
context = gx.get_context()
# Connect to a data source
datasource = context.sources.add_pandas_filesystem(
name="my_data",
base_directory="./data"
)
asset = datasource.add_csv_asset(name="orders", batching_regex=r"orders_(?P<date>\d{8})\.csv")
batch_request = asset.build_batch_request()
# Define expectations
validator = context.get_validator(batch_request=batch_request)
validator.expect_column_values_to_not_be_null("order_id")
validator.expect_column_values_to_be_between("amount", min_value=0, max_value=100000)
validator.expect_column_values_to_be_in_set("status", ["pending", "completed", "refunded"])
validator.expect_column_to_exist("customer_id")
# Save suite and run checkpoint
validator.save_expectation_suite()
results = context.run_checkpoint(checkpoint_name="orders_checkpoint")
print(results["success"]) # True / False
Great Expectations generiert Data Docs — menschenlesbare HTML-Reports, die zeigen, welche Expectations passed, welche failed, und Daten-Profile pro Spalte. Das ist der größte Differentiator.
Stärken:
- Spalten-Profiling und Verteilungs-Analyse
- Data Docs für stakeholder-taugliche Quality-Reports
- Funktioniert mit Pandas, Spark, SQL-Datenbanken
Schwächen:
- Konfiguration ist verbose und komplex
- Onboarding dauert Stunden, nicht Minuten
- Expectation-Suites pflegen, während sich Daten entwickeln, braucht Disziplin
Wann Great Expectations nutzen: Du brauchst Daten-Profiling neben Validierung, baust einen Data-Quality-Reporting-Layer für Nicht-Engineers, oder arbeitest außerhalb von dbt.
Soda Core
Soda nutzt eine zweckgebaute YAML-DSL namens SodaCL (Soda Checks Language). Liest sich wie Klartext und integriert sich sauber in Airflow, GitHub Actions oder jeden Orchestrator.
# checks/orders_checks.yml (SodaCL)
checks for orders:
- row_count > 0
- missing_count(order_id) = 0
- duplicate_count(order_id) = 0
- invalid_percent(status) < 1%:
valid values: [pending, completed, refunded, cancelled]
- avg(amount) between 10 and 5000
- freshness(order_date) < 24h
Mit der CLI ausgeführt:
# Bash: run Soda checks against a PostgreSQL table
soda scan -d my_postgres_connection -c configuration.yml checks/orders_checks.yml
Der freshness-Check ist ein Highlight: er validiert, dass Daten kürzlich aktualisiert wurden — etwas, das dbt-Tests nicht nativ ausdrücken können.
Stärken:
- Lesbares YAML ist auch für Analysten und Data Owner zugänglich, nicht nur Engineers
- Freshness-Checks eingebaut
- Saubere Orchestrator-Integration als Pipeline-Step
- Soda Cloud (SaaS) bietet Alerting und historisches Tracking
Schwächen:
- Komplexe Conditional-Logic ist in YAML unbequem
- Soda Cloud ist ein bezahltes Produkt (Soda Core ist kostenlos)
- Weniger reifes Ökosystem als Great Expectations
Wann Soda Core nutzen: Du willst Quality-Checks, die auch Nicht-Engineers lesen und ändern können. Funktioniert besonders gut als Pipeline-Gate in Airflow oder Prefect.
pytest für Datenpipelines
pytest ist ein General-Purpose-Python-Testing-Framework. Nicht datenspezifisch, aber unverzichtbar zum Testen des Python-Codes um deine Daten herum — Transformationsfunktionen, Schema-Mappings, Custom-Logik.
# Python (pytest): test a transformation function
import pytest
import pandas as pd
from my_pipeline.transforms import normalize_country_code, compute_revenue_bucket
def test_normalize_country_code_uppercase():
assert normalize_country_code("de") == "DE"
assert normalize_country_code("fr") == "FR"
def test_normalize_country_code_invalid_raises():
with pytest.raises(ValueError, match="Invalid country code"):
normalize_country_code("XX")
def test_compute_revenue_bucket():
df = pd.DataFrame({"amount": [5, 50, 500, 5000]})
result = compute_revenue_bucket(df)
assert list(result["bucket"]) == ["micro", "small", "medium", "large"]
def test_compute_revenue_bucket_empty_input():
df = pd.DataFrame({"amount": []})
result = compute_revenue_bucket(df)
assert len(result) == 0
pytest ist auch ausgezeichnet für Snapshot-Tests auf kleinen Referenz-Datasets — Fixture laden, Transformation laufen lassen, prüfen, dass der Output dem erwarteten Ergebnis entspricht:
# Python (pytest): snapshot test with fixture
import pandas as pd
def test_deduplication_logic(tmp_path):
input_data = pd.DataFrame({
"id": [1, 1, 2],
"value": ["a", "a_duplicate", "b"]
})
expected = pd.DataFrame({
"id": [1, 2],
"value": ["a", "b"]
})
result = deduplicate(input_data, key="id", keep="first")
pd.testing.assert_frame_equal(result.reset_index(drop=True), expected)
Wann pytest nutzen: Du schreibst Python-ETL-Code, Custom-Spark-Transformations oder Utility-Funktionen. Jede Funktion, die Daten transformiert, sollte einen Unit-Test haben.
Layern: alle vier zusammen
Diese Tools schließen sich nicht aus. Ein reifes Data-Team nutzt typischerweise alle vier auf verschiedenen Layern:
Layer 1 — Unit-Tests: pytest (testet Python-Transform-Logik)
Layer 2 — Model-Validation: dbt-Tests (testet SQL-Model-Output)
Layer 3 — Pipeline-Gates: Soda Core (Freshness, Volume, Cross-Tabellen-Checks)
Layer 4 — Profiling/Audits: Great Expectations (Onboarding neuer Quellen, Quality-Reports)
Zu versuchen, nur ein Tool für alle vier Layer zu nutzen, ist der Punkt, an dem Teams in Schwierigkeiten geraten. dbt-Tests sind super auf Layer 2, können aber Layer 1 nicht oder Freshness ausdrücken. pytest ist nutzlos auf Layer 2. Wähl das richtige Tool pro Layer.
Häufige Pitfalls
- Das Warehouse testen statt das Model: dbt-Tests laufen gegen materialisierte Tabellen. Wenn deine Quelldaten schon korrupt sind, bedeutet bestandene dbt-Tests nur, dass das Model die schlechten Daten getreu reproduziert hat. Ergänze Source-Tests.
- Kein Test für Volume: Eine stille Truncation (0 Zeilen geladen) besteht die meisten Tests. Immer einen
row_count > 0-Check ergänzen. - Über-Testen: Schreib nicht
not_null-Tests für jede Spalte in jedem Model. Konzentrier dich auf Spalten, die Downstream-Failures verursachen würden, wenn sie null wären. - Expectations, die nie aktualisiert werden: Eine Great-Expectations-Suite, die auf 6 Monaten Daten erstellt wurde, fällt um, wenn du ein neues Land ergänzt. Wartung ist der versteckte Kostenpunkt.
FAQ
Wenn ich nur ein Tool wählen darf — welches?
Bist du dbt-native: dbt-Tests. Bist du nicht auf dbt und brauchst etwas, das Nicht-Engineers lesen können: Soda Core. Bist du voll Python-zentriert: pytest + Great Expectations.
Kann ich dbt-Tests und Soda parallel betreiben?
Ja, üblicher Setup: dbt-Tests im dbt-Lauf, Soda als separater Pipeline-Step für Freshness und Cross-Tabellen-Checks. Doppelt geprüft ist nicht doppelt teuer — die Failures fangen unterschiedliche Klassen ab.
Wie verhindere ich, dass Tests zur Wartungslast werden?
Tests in Severity-Tiers staffeln (P0/P1/P2), nicht jedes Feld testen, sondern die mit echter Downstream-Auswirkung. Tests, die seit 6 Monaten nicht gefailt sind, sind Kandidaten zum Streichen oder Lockern.
Sind Data-Quality-Tools DSGVO-relevant?
Indirekt: gute Quality-Tests fangen Datenleckagen frühzeitig ab (z. B. eine Spalte, die plötzlich PII enthält), helfen bei Auskunftsrecht-Anfragen (Konsistenz-Checks) und sichern Retention-Pipelines.
Reicht Soda Cloud oder brauche ich GX?
Soda Cloud deckt 80 % der typischen Quality-Reporting-Needs. Wenn du echtes Profiling und Verteilungs-Analyse für unbekannte Datenquellen brauchst, ist GX immer noch das richtige Tool.
Wrap-up
Für die meisten dbt-nativen Teams: mit dbt-Tests starten, Soda Core für Freshness und Cross-Tabellen-Checks ergänzen. Great Expectations dazuholen, wenn du Daten-Profiling oder Quality-Reporting für nicht-technische Stakeholder brauchst. pytest immer dann, wenn deine Pipeline Python-Logik enthält, die testenswert ist.
Data Testing ist kein einzelnes Tool — es ist eine Disziplin, die über Layer hinweg angewandt wird. Teams, die das gut machen, behandeln Test-Failures wie CI/CD-Failures: nichts geht raus, bevor sie grün sind.
Weiterlesen
Stand: 14. Mai 2026.
Geschrieben von
Harbinger Team
Cloud-, Data- und AI-Engineer in DACH. Schreibt seit 2018 über infrastrukturkritische Tech-Entscheidungen — keine Marketing- Folien, sondern echte Trade-offs aus Production-Workloads.
Hat dir das geholfen?
Jede Woche ein neuer Artikel über DACH-Cloud, Data und AI — direkt in dein Postfach. Kein Spam, kein Marketing-Sprech.
Kein Spam. 1-Klick-Abmeldung. Datenschutz bei Loops.so.