【dbt Docs】Building a dbt Project - Tests
Tests
Related reference docs
-
Test command
dbt test
は、models
,sources
,snapshot
,seed
など dbtのコマンドに対してテストを走らせる。基本的に、リソース(モデルやスナップショット)は構成済みという前提
--select
フラグで、特定の条件のテストができる# run tests for one_specific_model $ dbt test --select one_specific_model # run tests for all models in package $ dbt test --select some_package.* # run only tests defined singularly $ dbt test --select test_type:singular # run only tests defined generically $ dbt test --select test_type:generic # run singular tests limited to one_specific_model $ dbt test --select one_specific_model,test_type:singular # run generic tests limited to one_specific_model $ dbt test --select one_specific_model,test_type:generic
-
Test properties
version: 2 models: - name: <model_name> tests: - <test_name>: <argument_name>: <argument_value> config: <test_config>: <config-value> columns: - name: <column_name> tests: - <test_name> - <test_name>: <argument_name>: <argument_value> config: <test_config>: <config-value>
- not_null
- unique
- accepted_values
- relationships
schama.ymlversion: 2 models: - name: orders columns: - name: customer_id tests: - relationships: to: ref('customers') field: id
- Test configurations
- Test selection examples
Getting started
(はじめに)
テストは、dbtプロジェクト内のモデルやその他のリソース(ソース、シード、スナップショットなど)について行うアサーションです。dbt test
を実行すると、dbtは、プロジェクトの各テストが成功したか失敗したかを通知します。
※アサーションとは:あるコードが実行される時に満たされるべき条件を記述して実行時にチェックする仕組み
test
は、SQLのクエリで、失敗するSQLを記載して、アサーションし、おかしなことが起きていないか?をチェックしています。他には、モデル内のユニーク制約やNull制約といったものをチェックする機構もあり、データのチェックが保証されます
※DWH製品は、構文上許容されている NOT NULLやPRIMARY KEYなどが実質動いていなかったりするが、そこを補完的にdbtにてデータのチェックを入れることで、「実質的に」PKey状態になっているか?などが検証できる。
dbtでテストを定義する方法は2つある
-
singular(特異な) test :失敗した行を返すSelect文を、
test
ディレクトリ内の.sql
に配置する。dbt test
コマンドで実行できる -
generic(一般的な) test : nullチェックとかPkeyチェックとか。
yml
ファイルに書いたり、.sql
のなかのtest
ブロックで定義したり。このテストは、モデルやカラム、ソースやスナップショット、シードでテストすることができる。
テストを定義することは、コードが正しく機能していることを確認するための優れた方法であり、コードが変更されたときのリグレッションを防ぐのに役立ちます。それらを何度も使用して、わずかなバリエーションで同様のアサーションを作成できるため、一般的なテストがはるかに一般的である傾向があります。これらは、dbtテストスイートの大部分を構成する必要があります
Singular tests(特異?テスト)
テストを定義する最も簡単な方法は、失敗したレコードを返す正確なSQLを作成することです。これらは単一の目的に使用できる1回限りのアサーションであるため、これらを「特異な(singular)」テストと呼びます。
これらのテストは、tests
ディレクトリ配下の .sql
ファイルです。( test-paths configで定義することも可能)。モデルと同じように作り、テスト定義では、Jinja( ref
関数やsource
関数など)が使用できる。.sql
ファイルには一つのselect
句が含まれ、1つのテストを定義する。
-- 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) as total_amount
from {{ ref('fct_payments' )}}
group by 1
having not(total_amount >= 0)
※カラム名などを変えるだけで使えるので、その意味では「特異」ではない。呼称的にはSingularだが、使い回せる。
Generic tests
(一般的なテスト)
これはnot_null
テストの中身。2つの引数がある。model
とcolum_name
。こちらでテンプレート化されている。
{% test not_null(model, column_name) %}
select *
from {{ model }}
where {{ column_name }} is null
{% endtest %}
デフォルトでは、以下のテストが利用できる
unique
not_null
accepted_values
relationship
version: 2
models:
- name: orders
columns:
- name: order_id
tests:
- unique
- not_null
- name: status
tests:
- accepted_values:
values: ['placed', 'shipped', 'completed', 'returned']
- name: customer_id
tests:
- relationships:
to: ref('customers')
field: id
-
order_id
は、unique
とnot_null
-
status
は、place, shipped, completed, returned
の値のみOK -
customer_id
は、customers.id
と同値(参照整合性)
More generic tests
(より一般的なテスト)
パッケージやマクロなどが公開されているのでそちらを使うのもあり( dbt-utils
や dbt-expections
など)
-
dbt-utils
- equal_rowcount : 比較対象のモデルと行数が一緒(JOINが・・とかのテストができそう)
- fewer_rows_than
- quality
- expression_is_true
- recency
- at_least_one
- not_constant
- cardinality_equaility
- unique_where
- not_null_where
- not_null_proportion : このテストは、列に存在する非NULL値の割合が、指定された範囲内であることを検証します。
- relationships_where
- mutually_exclusive_ranges:このテストは、与えられたlower_bound_columnとupper_bound_columnについて、下限と上限の間の範囲が他の行の範囲と重ならないことを確認するものである。
- unique_combination_of_columns
- acccceptged_range
- dbt-expections
- Table Shape
- Missing values, unique values, and types
- Sets and ranges
- String matching
- expect_column_value_lengths_to_equal
- expect_column_values_to_match_regex
- Aggregated functions
- expect_column_distinct_count_to_be_greater_than
- expect_column_max_to_be_between
- Multi-column
- expect_column_pair_values_A_to_be_greater_than_B
- Distributional functions
Example
テストをプロジェクトに追加するには、
- '.yml'ファイルを
models
ディレクトリに作成する。例えばmodels/schema.yml
models/schama.ymlversion: 2 models: - name: orders columns: - name: order_id 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
- テスト結果を確認する
- dbt Cloud : "Details" タブをチェック
- dbt CLI :
target/compiled
ディレクトリを確認
Unique test
Compiled SQL
select *
from (
select
order_id
from analytics.orders
where order_id is not null
group by order_id
having count(*) > 1
) validation_errors
Templatged SQL
from (
select
{{ column_name }}
from {{ model }}
where {{ column_name }} is not null
group by {{ column_name }}
having count(*) > 1
) validation_errors
Not null test
Compiled SQL
select *
from analytics.orders
where order_id is null
Templated SQL
select *
from {{ model }}
where {{ column_name }} is null
Storing test failures
--store-fallures
オプションを使うか、 configにstore_failures
を指定すると、テストクエリの結果をDWHのテーブルに保存する。デバッグに有用
- テスト結果は、デフォルトで
dbt_test__audit
に保存dbt_test__
の接頭辞のついたテーブル。schema
を使えば指定のスキーマに保尊することができる。 - テストの結果は、常に上書き(追記ではない)
FAQs
-
一度に1つのモデルをテストするにはどうすればよいですか?
--select
フラグで可能dbt test --select customers
-
テストの1つが失敗しましたが、どうすればデバッグできますか?
dbt Cloud
では、[Details]
dbt CLI
ではtarget/compiled/schama_tests
にコンパイル済みのSQLが記録されているのでそのSQLを実行して失敗内容を確認する -
プロジェクトにどのようなテストを追加する必要がありますか?
全てのモデルで、主キー(PrimaryKey)テストをすることがおすすめ(
unique
とnot_null
制約)
あとはsources
を用いて、ソースデータのデータ整合性テストを行うこともおすすめ -
テストはいつ実行する必要がありますか?
新しいコードを作成するとき(SQLを変更して既存のモデルを壊していないことを確認するため)、および本番環境で変換を実行するとき(ソースデータに関する仮定が引き続き有効であることを確認するため)にテストを実行する必要があります。
-
プロジェクトの`tests`ディレクトリ以外のディレクトリにテストを保存できますか?
デフォルトでは、単一のテストファイルが
tests
ディレクトリ(ただし、設定可能)
汎用のテスト定義がtests/generic
かmacros
に配置が想定されるたとえば、generic testが、
my_cool_test/generic/
の場合は、singular testはmy_cool_test
に -
ソースのみでテストを実行するにはどうすればよいですか?
$ dbt test --select souce:*
-
テスト失敗のしきい値を設定できますか?
v0.20.0
以降でerror_if
とwarn_if
で設定できるようになった。 -
2つの列の一意性をテストできますか?
いくつかの方法がある
- モデルに一意のキーを作成して、それをテストする方法
models.orders.sqlselect country_code || '-' || order_id as surrogate_key, ...
models/orders.ymlversion: 2 models: - name: orders columns: - name: surrogate_key tests: - unique
- 式(expression) でテストする
models/orders.ymlversion: 2 models: - name: orders tests: - unique: column_name: "(country_code || '-' || order_id)"
注意 たしかこの方法はあまり推奨されていないという記述を見た覚えがある。サポートしてないDWHがあるとか・・・
3.dbt_utils.unique_combination_of_columns
を使う方法
パフォーマンスに優れるため、大きなデータセットには有効models/orders.ymlversion: 2 models: - name: orders tests: - dbt_utils.unique_combination_of_columns: combination_of_columns: - country_code - order_id
Discussion