Добавление тестов данных в ваш DAG
Связанные справочные документы
Тесты теперь называются data tests, чтобы избежать путаницы с unit tests. YAML-ключ tests: по‑прежнему поддерживается как алиас для data_tests:. Подробнее см. в разделе New data_tests: syntax.
Обзор
Data tests — это утверждения, которые вы задаёте для своих моделей и других ресурсов в проекте dbt (например, sources, seeds и snapshots). Когда вы запускаете dbt test, dbt сообщает, проходит ли каждый тест в вашем проекте или завершается с ошибкой.
Вы можете использовать тесты данных для улучшения целостности SQL в каждой модели, делая утверждения о сгенерированных результатах. Из коробки вы можете проверить, содержит ли указанный столбец в модели только ненулевые значения, уникальные значения или значения, которые имеют соответствующее значение в другой модели (например, customer_id для order соответствует id в модели customers), и значения из указанного списка. Вы можете расширить тесты данных, чтобы они соответствовали бизнес-логике, специфичной для вашей организации — любое утверждение, которое вы можете сделать о своей модели в форме запроса select, может быть преобразовано в тест данных.
Тесты данных возвращают набор записей, которые не прошли проверку. Универсальные тесты данных (также известные как schema tests) определяются с помощью блоков test.
Как и почти все в dbt, тесты данных — это SQL-запросы. В частности, это операторы select, которые стремятся захватить "неудачные" записи, те, которые опровергают ваше утверждение. Если вы утверждаете, что столбец уникален в модели, тестовый запрос выбирает дубликаты; если вы утверждаете, что столбец никогда не бывает пустым, тест ищет пустые значения. Если тест данных возвращает ноль неудачных строк, он проходит, и ваше утверждение подтверждается.
В dbt есть два способа определения тестов данных:
- Сингулярный (singular) тест данных — это тестирование в самом простом виде: если вы можете написать SQL‑запрос, который возвращает строки с ошибками, вы можете сохранить этот запрос в
.sql‑файле внутри вашего каталога тестов. Теперь это тест данных, и он будет выполнен командойdbt test. - Обобщённый (generic) тест данных — это параметризованный запрос, который принимает аргументы. Сам запрос теста определяется в специальном блоке
test(аналогично macro). После определения вы можете ссылаться на обобщённый тест по имени в ваших.yml‑файлах — назначать его моделям, колонкам, источникам, снапшотам и сид‑таблицам. В dbt уже встроены четыре обобщённых теста данных, и мы считаем, что вам стоит ими пользоваться!
Определение тестов данных — отличный способ подтвердить, что ваши выходные и входные данные соответствуют ожиданиям, и помогает предотвратить регрессии при изменении вашего кода. Поскольку вы можете использовать их снова и снова, делая аналогичные утверждения с небольшими вариациями, общие тесты данных, как правило, гораздо более распространены — они должны составлять основную часть вашего набора тестов данных dbt. Тем не менее, оба способа определения тестов данных имеют свое время и место.
Если вы только начинаете работать с dbt, мы рекомендуем ознакомиться с нашим онлайн-курсом dbt Fundamentals или кратким руководством, чтобы создать свой первый dbt‑проект с моделями и тестами.
Единичные тесты данных
Самый простой способ определить тест данных — это написать точный SQL, который вернет неудачные записи. Мы называем их "единичными" тестами данных, потому что это одноразовые утверждения, используемые для одной цели.
Эти тесты определяются в файлах .sql, обычно в вашем каталоге tests (как определено вашей конфигурацией test-paths). Вы можете использовать Jinja (включая ref и source) в определении теста, так же как и при создании моделей. Каждый файл .sql содержит один оператор select и определяет один тест данных:
-- Возвраты имеют отрицательную сумму, поэтому общая сумма всегда должна быть >= 0.
-- Поэтому возвращаем записи, где total_amount < 0, чтобы тест не прошел.
select
order_id,
sum(amount) as total_amount
from {{ ref('fct_payments') }}
group by 1
having total_amount < 0
Имя этого теста — это имя файла: assert_total_payment_amount_is_positive.
Примечание:
- Не ставьте точку с запятой (
;) в конце SQL‑запроса в файлах с одиночными тестами, так как это может привести к сбою выполнения data‑теста. - Одиночные data‑тесты, размещённые в директории
tests, автоматически выполняются при запускеdbt test. Не ссылайтесь на одиночные тесты вmodel_name.yml, так как они не рассматриваются как generic‑тесты или макросы, и это приведёт к ошибке.
Чтобы добавить описание к одиночному data‑тесту в вашем проекте, добавьте файл .yml в директорию tests, например tests/schema.yml, со следующим содержимым:
data_tests:
- name: assert_total_payment_amount_is_positive
description: >
Возвраты имеют отрицательную сумму, поэтому общая сумма всегда должна быть >= 0.
Поэтому возвращаем записи, где общая сумма < 0, чтобы тест не прошел.
Единичные тесты данных настолько просты, что вы можете обнаружить, что пишете одну и ту же базовую структуру снова и снова, только меняя имя столбца или модели. В этот момент тест уже не так уж и единичен! В этом случае мы рекомендуем общие тесты данных.
Общие тесты данных
Некоторые тесты данных являются общими: их можно использовать снова и снова. Общий тест данных определяется в блоке test, который содержит параметризованный запрос и принимает аргументы. Он может выглядеть так:
{% test not_null(model, column_name) %}
select *
from {{ model }}
where {{ column_name }} is null
{% endtest %}
Вы заметите, что здесь есть два аргумента — model и column_name, — которые затем подставляются в запрос с помощью шаблонов. Именно это делает тест данных «обобщённым» (generic): его можно определить для любого количества колонок и для любого количества моделей, а dbt соответствующим образом передаст значения model и column_name. После того как такой обобщённый тест определён, его можно добавить как свойство к любой существующей модели (или источнику, seed или snapshot). Эти свойства добавляются в файлах .yml, расположенных в той же директории, что и ваш ресурс.
Если это ваш первый опыт работы с добавлением свойств к ресурсу, ознакомьтесь с документацией по объявлению свойств.
Из коробки dbt поставляется с четырьмя уже определенными общими тестами данных: unique, not_null, accepted_values и relationships. Вот полный пример использования этих тестов на модели orders:
models:
- name: orders
columns:
- name: order_id
data_tests:
- unique
- not_null
- name: status
data_tests:
- accepted_values:
arguments: # available in v1.10.5 and higher. Older versions can set the <argument_name> as the top-level property.
values: ['placed', 'shipped', 'completed', 'returned']
- name: customer_id
data_tests:
- relationships:
arguments:
to: ref('customers')
field: id
На простом языке, эти тесты данных переводятся как:
unique: столбецorder_idв моделиordersдолжен быть уникальнымnot_null: столбецorder_idв моделиordersне должен содержать пустых значенийaccepted_values: столбецstatusвordersдолжен быть одним из'placed','shipped','completed'или'returned'relationships: каждыйcustomer_idв моделиordersсуществует какidвcustomerstable (также известная как ссылочная целостность)
За кулисами dbt строит select запрос для каждого теста данных, используя параметризованный запрос из общего блока теста. Эти запросы возвращают строки, где ваше утверждение не является истинным; если тест возвращает ноль строк, ваше утверждение проходит.
Вы можете найти больше информации об этих тестах данных, а также о дополнительных настройках (включая severity и tags) в разделе справки. Также вы можете добавлять описания в Jinja‑макрос, который реализует основную логику обобщённого теста данных. Подробнее см. в разделе Add description to generic data test logic.
Больше общих тестов данных
Этих четырёх тестов достаточно, чтобы начать работу. Очень скоро вы обнаружите, что хотите использовать более широкий набор тестов данных — и это хорошо! Вы также можете установить обобщённые (generic) тесты данных из пакета или написать свои собственные, чтобы использовать их (и переиспользовать) в рамках проекта dbt. Подробнее об этом читайте в руководстве по созданию собственных generic‑тестов данных.
В некоторых open‑source пакетах уже определены generic‑тесты данных, например в dbt-utils и dbt-expectations — перейдите к документации по пакетам, чтобы узнать больше!
Пример
Чтобы добавить generic (или «schema») тест данных в ваш проект:
- Добавьте файл
.ymlв директориюmodels, напримерmodels/schema.yml, со следующим содержимым (возможно, вам потребуется скорректировать значенияname:для уже существующей модели).
models:
- name: orders
columns:
- name: order_id
data_tests:
- unique
- not_null
- Запустите
команду dbt test:
$ dbt test
Found 3 models, 2 tests, 0 snapshots, 0 analyses, 130 macros, 0 operations, 0 seed files, 0 sources
17:31:05 | Concurrency: 1 threads (target='learn')
17:31:05 |
17:31:05 | 1 of 2 START test not_null_order_order_id..................... [RUN]
17:31:06 | 1 of 2 PASS not_null_order_order_id........................... [PASS in 0.99s]
17:31:06 | 2 of 2 START test unique_order_order_id....................... [RUN]
17:31:07 | 2 of 2 PASS unique_order_order_id............................. [PASS in 0.79s]
17:31:07 |
17:31:07 | Finished running 2 tests in 7.17s.
Completed successfully
Done. PASS=2 WARN=0 ERROR=0 SKIP=0 TOTAL=2
- Посмотрите SQL, который выполняет dbt, одним из следующих способов:
- dbt: проверьте вкладку Details.
- dbt Core: проверьте директорию
target/compiled.
Тест на уникальность
- Скомпилированный SQL
- Шаблонизированный SQL
select *
from (
select
order_id
from analytics.orders
where order_id is not null
group by order_id
having count(*) > 1
) validation_errors
select *
from (
select
{{ column_name }}
from {{ model }}
where {{ column_name }} is not null
group by {{ column_name }}
having count(*) > 1
) validation_errors
Тест на отсутствие null
- Скомпилированный SQL
- Шаблонизированный SQL
select *
from analytics.orders
where order_id is null
select *
from {{ model }}
where {{ column_name }} is null
Хранение результатов неудачных тестов данных
Обычно запрос теста данных вычисляет неудачи в процессе своего выполнения. Если вы установите необязательный флаг --store-failures, конфигурацию store_failures или конфигурацию store_failures_as, dbt сначала сохранит результаты тестового запроса в таблицу в базе данных, а затем выполнит запрос к этой таблице, чтобы вычислить количество неудач.
Этот рабочий процесс позволяет вам быстрее запрашивать и изучать неудачные записи в процессе разработки:
Обратите внимание: если вы выбираете сохранение результатов неудачных data tests:
- Таблицы с результатами тестов по умолчанию создаются в схеме с суффиксом или именем
dbt_test__audit. Это значение можно изменить, указав параметрschemaв конфигурации. (Подробнее о правилах именования схем см. в разделе using custom schemas.) - Результаты теста всегда заменяют предыдущие неудачные результаты для того же самого теста.
Новый синтаксис data_tests:
Исторически data tests в dbt назывались просто «tests», поскольку это была единственная форма тестирования. С появлением unit tests ключ был переименован с tests: на data_tests:.
dbt по‑прежнему поддерживает ключ tests: в ваших YML‑файлах конфигурации из соображений обратной совместимости, и вы можете встретить его использование в документации. Однако нельзя одновременно использовать ключи tests и data_tests, связанные с одним и тем же ресурсом (например, с одной моделью).
models:
- name: orders
columns:
- name: order_id
data_tests:
- unique
- not_null
data_tests:
+store_failures: true
