はじめに
dbtではモデルをテストする機能があります。テストは品質の低いデータの混入を検知したり、データの品質を保つために使われます。
テストを定義する方法は次の2種類があります。
- Singularテスト
- Genericテスト
テストを定義し、dbt test
コマンドを実行するとテストが実施されます。
Singular テスト
Singularテストではdbt_project.yml
のtest-paths
に指定したディレクトリ(デフォルトでは/tests
)に.sql
ファイルとしてテスト用のコードを記述します。
テストコードは存在してはいけない行を検索するSELECT
文を記述します。
例えば、fct_payments
というモデルがあり、amount
がポジティブの値であるかどうかをテストしたい場合は次のようなSQLを記述します。
-- Refunds have a negative amount, so the total amount should always be >= 0.
-- Therefore return records where this isn't true to make the test fail
select
order_id,
sum(amount)
from {{ ref('fct_payments')}}
group by 1
having not(amount >= 0)
dbt test
コマンドを実行するとテストコードが実行され、行が検索されてしまった場合はテストが失敗します。テストが失敗すると次のようになります。
$ dbt test
14:19:07 Running with dbt=1.0.4
14:19:07 Found 1 model, 1 test, 0 snapshots, 0 analyses, 165 macros, 0 operations, 0 seed files, 2 sources, 0 exposures, 0 metrics
14:19:07
14:19:07 Concurrency: 1 threads (target='dev')
14:19:07
14:19:07 1 of 1 START test assert_amount_is_positive........................ [RUN]
14:19:07 1 of 1 FAIL 1 assert_amount_is_positive............................ [FAIL 1 in 0.05s]
14:19:07
14:19:07 Finished running 1 test in 0.23s.
14:19:07
14:19:07 Completed with 1 error and 0 warnings:
14:19:07
14:19:07 Failure in test assert_fct_payments (tests/assert_amount_is_positive.sql)
14:19:07 Got 1 result, configured to fail if != 0
14:19:07
14:19:07 compiled SQL at target/compiled/my_dbt_proj/tests/assert_amount_is_positive.sql
14:19:07
14:19:07 Done. PASS=0 WARN=0 ERROR=1 SKIP=0 TOTAL=1
テストに成功すると次のようになります。
$ dbt test
14:21:33 Running with dbt=1.0.4
14:21:33 Found 1 model, 1 test, 0 snapshots, 0 analyses, 165 macros, 0 operations, 0 seed files, 2 sources, 0 exposures, 0 metrics
14:21:33
14:21:33 Concurrency: 1 threads (target='dev')
14:21:33
14:21:33 1 of 1 START test assert_amount_is_positive....................... [RUN]
14:21:33 1 of 1 PASS assert_amount_is_positive............................. [PASS in 0.05s]
14:21:33
14:21:33 Finished running 1 test in 0.23s.
14:21:33
14:21:33 Completed successfully
14:21:33
14:21:33 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
Generic テスト
Genericテストでは、dbtが標準で用意している4つのスキーマテストを使ってテストします。
unique
カラムがユニークであるかどうかnot_null
カラムにNULL値が存在しないかどうかaccepted_values
カラムの値が指定した値になっているかどうかrelationships
参照整合性を満たしているかどうか
例えば次のように.yml
ファイルに記述します。
version: 2
models:
- name: customers
columns:
- name: customer_id
tests:
- unique
- not_null
- name: stg_customers
columns:
- name: customer_id
tests:
- unique
- not_null
- name: stg_orders
columns:
- name: order_id
tests:
- unique
- not_null
- name: status
tests:
- accepted_values:
values: ['placed', 'shipped', 'completed', 'return_pending', 'returned']
- name: customer_id
tests:
- not_null
- relationships:
to: ref('stg_customers')
field: customer_id
dbt test
を実行すると上記のyml
ファイルの内容のテストが走ります。
また、このスキーマテストは自身で拡張することも可能で、dbt-utils といった外部パッケージを利用することで拡張します。
カスタム Generic テスト
標準のGenericテストでは機能が不足している場合、カスタムGenericテストを作成することができます。
カスタムGeneric testではtests/generic
ディレクトリもしくはmacros/
ディレクトリにtest
ブロックを使ったSQLファイルを記述します。
{% test is_even(model, column_name) %}
with validation as (
select
{{ column_name }} as even_field
from {{ model }}
),
validation_errors as (
select even_field
from validation
where (even_field % 2) = 1
)
select *
from validation_errors
{% endtest %}
データモデルのファイルと同じ階層に.yml
ファイルを作成し、次のようにtests
セクションにテスト名を記述します。
version: 2
models:
- name: users
columns:
- name: favorite_number
tests:
- is_even
参考