Тестування конвеєрів даних
1) Навіщо тестувати конвеєри даних
Конвеєри даних (ingest → transform → serve) - критична інфраструктура для звітності, ML і операційних рішень. Помилки перетворюються на невірні метрики, фрод-сигнали і грошові втрати. Тестування забезпечує:- Достовірність (correctness) і стабільність (resilience).
- Передбачуваність змін (schema/logic evolution).
- Дотримання SLO по свіжості, повноті, латентності.
- Швидкий випуск (швидкість релізів) за рахунок автоматизованої перевірки.
2) Піраміда тестування даних
Знизу вгору: багато швидких локальних тестів → менше інтеграційних → трохи end-to-end.
1. Юніт-тести трансформацій (функції, UDF, SQL-види, dbt-моделі).
2. Тести якості даних (правила свіжості/повноти/унікальності/діапазонів).
3. Контракти і схеми (schema/contract tests, еволюція).
4. Інтеграційні тести пайплайна (DAG: ingest ↔ storage ↔ transform ↔ marts).
5. E2E-тести (від джерела до вітрини/API), включаючи права (RLS/CLS) і експорт.
6. Навантажувальні/продуктивність (об'єм, швидкість, cost-to-serve).
7. Хаос-тести даних (затримки, дублікати, out-of-order, недоступність).
3) Типи тестів: що саме перевіряємо
3. 1 Юніт-тести логіки
Чисті функції трансформацій; property-based (інваріанти: ідемпотентність, монотонність).
SQL/DBT: порівняння результату з еталоном (golden set), заборона'SELECT', перевірка фільтра за часом.
3. 2 Тести якості даних (DQ)
Свіжість: затримка вітрин ≤ цільового порогу.
Повнота: очікувана кількість/частка заповненості.
Унікальність: ключі без дублікатів.
Доменні правила: діапазони, референціальна цілісність, бізнес-інваріанти.
Аномалії: outliers, сплески дублікатів, розриви часу.
3. 3 Контракти і схеми
Сумісність змін (SemVer: MAJOR/MINOR/PATCH).
Наявність обов'язкових колонок, типів, обмежень.
Зафіксовані семантики KPI: формули і вікна агрегацій.
3. 4 Інтеграційні та E2E
Цілісність DAG: тригери, залежності, ідемпотентний повтор.
Повний шлях: джерело → raw → curated → marts → BI/API; RLS/CLS.
3. 5 Продуктивність і витрати
p95/p99 латентності джобів, throughput (rows/s), обсяг/вартість.
Тести регресій продуктивності і ліміти на скани.
3. 6 Безпека і приватність
Маскування PII/PCI (детермінована токенізація).
Перевірка RLS/CLS: користувачі бачать тільки своє.
Експорт/снепшоти: відсутність «сирих» персональних полів.
4) Специфіка стрімінгу (Kafka/Flink/Spark Structured Streaming)
Watermarks и lateness: тести вікон з запізнілими подіями (T + Δ), коректні перерахунки.
Exactly-once за змістом: дедуп по'event _ id', ідемпотентний запис (upsert/merge).
Out-of-order: інваріанти на агрегати по'event _ time'; фіксуємо'ingested _ at'.
Втрата/повтор: симулюємо дроп/реігру партій, перевіряємо коректність вітрин.
5) Ідемпотентність і детермінізм (що і як тестувати)
Повторний запуск кроку дає той же результат (при однакових параметрах вікна).
Запис - через staging і atomic swap.
Merge-логіка з SCD1/SCD2 покрита тестами конфліктів (last-write-wins, source priority).
Детермінованість UDF/агрегатів: однакові входи → однакові виходи.
6) Управління тест-даними
Golden datasets: малі еталони з ручною валідацією.
Синтетика + фабрики даних: покриття країв домену (nulls, extreme values, Unicode, TZ).
Де-ідентифіковані прод-семпли: відповідність приватності.
Шаруваті фікстури: сирі події, проміжні шари, підсумкові вітрини.
7) Контракти даних: приклад і правила
YAML-контракт (спрощено):yaml dataset: orders schema:
- name: order_id; type: string; unique: true
- name: user_id; type: string; not_null: true
- name: amount; type: decimal(18,2); min: 0
- name: event_time; type: timestamp; tz: UTC freshness_sla: 10m dq_rules:
- "pct_null(user_id) < 0. 1%"
- "duplicates(order_id) = 0"
- "sum(amount) >= 0"
evolution:
allowed_minor_additions: true breaking_changes_require: approval: 'data-governance'
actions_on_violation:
- quarantine_partition
- replay_last_60m
8) Спостережуваність і тести SLO
Експорт метрик: Freshness, Completeness, Uniqueness, Latency в Grafana/Prometheus.
SLO-алерти як «червоні» юніт-тести в проді (Synthetics).
Репорти регресій: «після релізу X p95 ↑ на 40%».
9) CI/CD і середовища
CI: юніт + DQ + контракти на PR; schema-diff; статичний аналіз SQL (лінтер).
Пісочниця/staging: прогін інтеграційних і e2e, хаос-тестів з безпечними даними.
Feature-flags: канарні джоби/моделі/формули.
Каталогізація: версія схем, формул KPI, lineage; автоматичне оновлення документації.
10) Хаос-тестування даних (Chaos-Data)
Ін'єкція дублікатів/перепусток, затримок, out-of-order.
Падіння брокера/партії, «биті» файли, schema drift.
Валідуємо: авто-ремонт (replay/backfill), quarantine і алерти, MTTR-data.
11) Навантажувальне і вартість
Генератори трафіку з профілем р95/піки.
Ліміти на скан/крок (bytes scanned, time caps).
A/B профілювальник вартості: «стара» vs «нова» модель/запит.
12) Інструменти (зразкові класи)
DQ/Контракти: dbt tests, Great Expectations, Deequ, Soda, Custom linters.
Оркестрація: Airflow/Dagster/Argo/Prefect (оператори для тестів на кожному кроці).
Платформи: BigQuery/Snowflake/Redshift/ClickHouse/Delta/Iceberg/Hudi.
Стрімінг: Kafka, Flink, Spark Streaming; TestContainers для локальних середовищ.
Observability: Prometheus/Grafana/Otel; каталоги DataHub/Amundsen/Collibra.
13) Антипатерни
«Тестувати нічого - це просто SQL»: немає юнітів і DQ → ламаються метрики.
Тільки E2E: повільно, нестабільно, причини поломок не ясні.
SELECT: ламається при MINOR-еволюції.
Live-читання OLTP в тестах: нестабільність і флейки.
Відсутність golden-наборів: немає чим порівнювати результати.
Немає тестів ідемпотентності: повторний запуск псує дані.
Забутий стрімінг: не тестуються lateness/out-of-order/повторна доставка.
14) Дорожня карта впровадження
1. Базис: юніт-тести трансформацій, golden-набори, лінтер SQL, DQ-правила top-10 вітрин.
2. Контракти: schema-diff в CI, SemVer, автоматичні перевірки сумісності.
3. Інтеграції: DAG-тести, idempotency, e2e для критичних потоків.
4. Стрімінг: тесты watermarks/lateness, dedup/idempotent sinks.
5. SLO і хаос: метрики якості в проді, алерти, хаос-сценарії, MTTR-цілі.
6. Оптимізація: перф-регресії, бюджет-гварди, канарні релізи.
15) Чек-лист перед релізом
- Юніт-тести покривають ключові трансформації і UDF.
- DQ-правила для свіжості/повноти/унікальності/діапазонів проходять.
- Контракти і schema-diff зелені; немає ламаючих змін без аппрува.
- Ідемпотентність перевірена; atomic sink/merge працює.
- Стрімінг: watermarks/late data/out-of-order покриті; dedup на місці.
- SLO-метрики експонуються; алерти сконфігуровані; runbooks є.
- Тест-дані безпечні; PII масковані; RLS/CLS перевірені.
- Перф-регресій немає; ліміти на скани/час дотримані.
- Хаос-тести базових сценаріїв пройшли; MTTR-цільовий досяжний.
16) Приклади міні-шаблонів
16. 1 Юніт-тест SQL (псевдо-dbt):
sql
-- tests/assert_positive_amount. sql select count() as c from {{ ref('fct_payments') }}
where amount < 0 having c = 0
16. 2 Правило свіжості (Great Expectations-стиль):
yaml expect_table_row_count_to_be_between:
min_value: 1000 mostly: 0. 99 expect_column_values_to_not_be_null:
column: user_id expect_column_values_to_be_unique:
column: txn_id
16. 3 Перевірка lateness в стрімі (псевдо-код):
python emit(events_out_of_window <= threshold)
emit(reprocessed_events == late_events_detected)
16. 4 Contract-test (schema-diff CI):
bash schema-diff --current models/orders. yml --target prod_schema. yml --semver
17) Підсумок
Тестування конвеєрів даних - це системна дисципліна, а не набір розрізнених перевірок. Поєднайте піраміду тестів, контракти і спостережуваність з практиками ідемпотентності, еволюції схем і стрімінгових інваріантів. Тоді релізи стануть швидкими, інциденти - рідкісними і короткими, а довіра до даних - стійким.