Раздел 26 · Data Engineering

Свои тесты: singular, generic и unit

junior~15 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

Встроенные тесты из прошлого урока ловят дубли и пустые ключи. У «Гонца» есть правила, которых в этом списке нет. Доставку не могут закрыть раньше, чем курьер забрал заказ, а в сырых данных таких заказов 24: у приложения курьера сбиваются часы. Цена и расстояние должны быть больше нуля. И главное: формула опоздания в int_deliveries должна считать правильно. Отто принимает по ней решения о премиях курьерам, ошибка в знаке стоит денег.

Три проверки в автосервисе

Механик проверяет машину тремя способами. Есть разовая проверка под конкретную жалобу: «посмотрите, почему стучит справа». Есть стандартный чек-лист, который прикладывают к любой машине: давление в шинах, уровень масла. И есть стенд, на котором двигатель гоняют без машины: подают топливо по расписанию и смотрят, выдаёт ли он нужные обороты.

В dbt те же три вида своих тестов: singular под одно правило, свой generic как пункт чек-листа и unit-тест как стенд для логики модели.

Singular-тест: файл с запросом

Singular-тест это обычный файл с SELECT в папке tests/. Правило то же, что у встроенных тестов: запрос ищет плохие строки, ноль строк означает успех.

-- tests/assert_delivered_after_picked_up.sql
{{ config(severity='warn') }}

-- Доставку не могут закрыть раньше, чем курьер забрал заказ.
select order_id, picked_up_at, delivered_at
from {{ ref('stg_orders') }}
where delivered_at < picked_up_at

Имя теста берётся из имени файла. ref() здесь так же обязателен, как в моделях: по нему dbt понимает, к какой модели относится тест, и запускает его после неё. config() в начале файла задаёт строгость. Про 24 сбоя часов мы знаем, int_deliveries их отбрасывает, поэтому тест только предупреждает.

Свой generic-тест: пункт чек-листа

Правило «значение больше нуля» нужно и цене, и расстоянию, и потом пригодится в других моделях. Писать singular-тест на каждую колонку скучно. Свой generic-тест пишется один раз блоком {% test %} в папке tests/generic/:

-- tests/generic/positive.sql
{% test positive(model, column_name) %}
select {{ column_name }}
from {{ model }}
where {{ column_name }} <= 0
{% endtest %}

Это почти макрос из урока 13: тело это шаблон запроса. Аргументы model и column_name dbt подставит сам, когда тест применят к колонке в YAML:

models:
  - name: stg_orders
    columns:
      - name: price_rub
        data_tests: [positive]
      - name: distance_km
        data_tests: [positive]

Получаются два теста: positive_stg_orders_price_rub и positive_stg_orders_distance_km. Если тесту нужны свои параметры, их добавляют в заголовок, {% test at_least(model, column_name, min_value) %}, и передают в YAML под arguments.

урок из курса

Урок из курса «Data Engineering». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.