Тесты и документация¶
dbt позволяет не просто строить таблицы, а проверять, что данные в них корректны. Тесты запускаются после каждой сборки и ловят ошибки до того, как они попадут в отчёты.
Зачем тестировать данные¶
Без тестов типичные проблемы обнаруживаются поздно:
| Проблема | Как проявляется |
|---|---|
| Дубликаты ключей | Отчёт показывает завышенную выручку |
| NULL в обязательных полях | Дашборд ломается или показывает пустоты |
| Неожиданные значения | Статус 'test' попадает в продуктовые метрики |
| Битые связи (FK) | JOIN теряет строки, аналитик не замечает |
dbt-тесты — это SQL-запросы, которые должны вернуть 0 строк. Если тест возвращает строки — значит, найдены проблемные записи.
Встроенные тесты (generic tests)¶
Четыре теста «из коробки», которые покрывают большинство проверок:
unique¶
Проверяет, что в колонке нет дубликатов:
Под капотом dbt генерирует:
not_null¶
Проверяет, что в колонке нет NULL:
accepted_values¶
Проверяет, что все значения — из заданного списка:
columns:
- name: status
tests:
- accepted_values:
values: ['paid', 'pending', 'cancelled', 'refunded']
relationships¶
Проверяет целостность внешнего ключа — все значения существуют в другой таблице:
Под капотом:
Комбинирование тестов¶
На одну колонку можно навесить несколько тестов:
# models/staging/schema.yml
models:
- name: stg_orders
columns:
- name: order_id
tests:
- unique
- not_null
- name: user_id
tests:
- not_null
- relationships:
to: ref('stg_users')
field: user_id
- name: status
tests:
- not_null
- accepted_values:
values: ['paid', 'pending', 'cancelled', 'refunded']
Кастомные тесты (singular tests)¶
Когда встроенных тестов не хватает — пиши SQL-запрос в папку tests/. Тест считается пройденным, если запрос вернул 0 строк.
-- tests/assert_positive_revenue.sql
-- Выручка не может быть отрицательной
SELECT
order_id,
revenue
FROM {{ ref('fct_revenue') }}
WHERE revenue < 0
-- tests/assert_orders_have_items.sql
-- У каждого заказа должна быть хотя бы одна позиция
SELECT
o.order_id
FROM {{ ref('stg_orders') }} o
LEFT JOIN {{ ref('stg_order_items') }} oi
ON o.order_id = oi.order_id
WHERE oi.order_id IS NULL
Именование кастомных тестов
Называй тесты с префиксом assert_ — сразу понятно, что проверяется: assert_positive_revenue, assert_no_orphan_payments.
Конфигурация тестов¶
severity — жёсткость теста¶
По умолчанию провал теста = ошибка (ERROR). Можно снизить до предупреждения:
where — фильтрация¶
Запускать тест только для части данных:
error_if и warn_if — пороги¶
Допустить определённое количество нарушений:
columns:
- name: email
tests:
- not_null:
error_if: ">100" # ошибка, если больше 100 NULL
warn_if: ">10" # предупреждение, если больше 10
schema.yml — описание и документация¶
Файл schema.yml выполняет две задачи: конфигурирует тесты и описывает модели для документации.
# models/marts/schema.yml
version: 2
models:
- name: fct_revenue
description: "Таблица выручки: одна строка = один оплаченный заказ"
columns:
- name: order_id
description: "Уникальный идентификатор заказа"
tests:
- unique
- not_null
- name: user_id
description: "ID покупателя"
tests:
- not_null
- relationships:
to: ref('dim_users')
field: user_id
- name: revenue
description: "Сумма заказа в рублях"
tests:
- not_null
- name: dim_users
description: "Справочник пользователей"
columns:
- name: user_id
description: "Уникальный идентификатор пользователя"
tests:
- unique
- not_null
Описание источников (sources)¶
Источники описываются в отдельном YAML:
# models/staging/sources.yml
version: 2
sources:
- name: raw
description: "Сырые данные из продуктовой БД"
schema: public
tables:
- name: orders
description: "Заказы пользователей"
columns:
- name: id
description: "PK заказа"
- name: status
description: "Статус: paid, pending, cancelled"
- name: users
description: "Пользователи системы"
Проверка свежести источников¶
dbt может проверять, что данные в источнике не устарели:
sources:
- name: raw
freshness:
warn_after:
count: 12
period: hour
error_after:
count: 24
period: hour
loaded_at_field: _etl_loaded_at
tables:
- name: orders
- name: users
Команда для проверки:
Если данные в таблице orders не обновлялись больше 12 часов — предупреждение, больше 24 — ошибка.
Генерация документации¶
dbt собирает описания из schema.yml, строит граф зависимостей и генерирует интерактивный сайт:
# Сгенерировать документацию
dbt docs generate
# Запустить локальный сервер
dbt docs serve --port 8080
На сайте документации:
- Каталог моделей — описание каждой модели и её колонок
- Граф зависимостей (Lineage Graph) — визуализация связей между моделями
- SQL-код — скомпилированный и исходный SQL каждой модели
Документация рядом с кодом
Описания хранятся в schema.yml рядом с моделями. Когда меняется SQL — обновляешь описание в том же PR. Документация не устаревает.
Команды для тестирования¶
# Запустить все тесты
dbt test
# Тесты для одной модели
dbt test --select stg_orders
# Тесты для модели и всех зависимостей
dbt test --select +fct_revenue
# Сборка + тесты (рекомендуемый способ)
dbt build
# Только тесты определённого типа
dbt test --select test_type:singular # только кастомные
dbt test --select test_type:generic # только встроенные
dbt build — запускает модели и тесты в правильном порядке: сначала модель, потом её тесты, потом зависимые модели.
dbt в CI/CD¶
Типичный пайплайн в CI:
# .github/workflows/dbt.yml (пример для GitHub Actions)
name: dbt CI
on:
pull_request:
paths:
- 'models/**'
- 'tests/**'
- 'macros/**'
jobs:
dbt-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dbt
run: pip install dbt-postgres
- name: Run dbt build
run: dbt build --target ci
env:
DBT_PROFILES_DIR: ./ci
Что проверяет CI:
- dbt compile — SQL корректен, нет синтаксических ошибок
- dbt run — модели успешно создаются в тестовой БД
- dbt test — все тесты данных проходят
CI-среда — отдельная БД
Для CI создай отдельный target в profiles.yml с тестовой базой. Никогда не запускай CI-тесты на продуктовой БД.
Что запомнить¶
- Четыре встроенных теста:
unique,not_null,accepted_values,relationships - Кастомные тесты — SQL в
tests/, возвращают проблемные строки (0 строк = тест пройден) schema.yml= тесты + документация в одном файлеdbt build= модели + тесты в правильном порядкеseverity: warn— тест предупреждает, но не останавливает сборку- Source freshness — проверяет, что данные не устарели
- В CI:
dbt build --target ciна отдельной базе
Проверь себя¶
Источники¶
- dbt Documentation: Tests — встроенные и кастомные тесты
- dbt Documentation: Documentation — генерация документации из YAML
- dbt Documentation: Sources — описание и проверка источников
- dbt Documentation: Source freshness — мониторинг свежести данных