GH GambleHub

Тестування конвеєрів даних

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) Підсумок

Тестування конвеєрів даних - це системна дисципліна, а не набір розрізнених перевірок. Поєднайте піраміду тестів, контракти і спостережуваність з практиками ідемпотентності, еволюції схем і стрімінгових інваріантів. Тоді релізи стануть швидкими, інциденти - рідкісними і короткими, а довіра до даних - стійким.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Telegram
@Gamble_GC
Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.