この記事は?
dbtのunit testを触ってみたメモです。
環境
- Cloud IDE
- version: versionless
- unit test は1.7までは使えないため、versionless(1.8+)にしてください。(2024年12月9日現在)
- DWHはsnowflake
unit testが動作するまでにやったこと
- ソースmodelの準備
- テスト対象modelの準備
- テスト用ymlの作成
- テストの実行
- エラー修正
ソースmodelの準備
テスト対象のmodelの元となるmodelの準備です。
社員番号と社員名が記載してある単純なmodelです。
select
emp_id,
emp_name
from
{{ ref("employee") }}
今回はテストを単純化するためにソース用のmodelを作成ました。
実際の環境ではソースmodelは作成しません(すでにあるmodelを使用)。
- 社員番号(emp_id)
- 0埋めの数字4桁
- スプレッドシートで取り込んでいるため、桁落ちしているレコードがある
- 社員名(emp_name)
- 姓名は半角スペースで区切られている
テスト対象modelの準備
テスト対象modelの準備です。
ソースmodelを変換して、実際に使用するmodelを作成します。
select
iff(len(emp_id) < 4, lpad(emp_id, '0', 4), emp_id) as emp_id,
trim(split(emp_name, ' ')[0], '"') as family_name,
trim(split(emp_name, ' ')[1], '"') as first_name
from
{{ ref("my_test_raw") }}
- 社員番号(emp_id)
- 4桁に満たない(0埋めが外れている)場合
- 先頭に'0'を4文字になるまで埋める
- 4桁以上の場合
- emp_idをそのまま使用
- 4桁に満たない(0埋めが外れている)場合
- 姓(family_name)
- 社員名を半角スペースで分割して、前半を姓として使用
- splitの仕様で「"」(ダブルクォート)が付加されるため、trimeで「"」を除去
- 名(fisrt_name)
- 社員名を半角スペースで分割して、後半を姓として使用
- splitの仕様で「"」(ダブルクォート)が付加されるため、trimeで「"」を除去
テスト用ymlの作成
テスト用ymlを作成します。
version: 2
unit_tests:
- name: test_my_test
model:
my_test
# givenは入力する値を定義する
given:
# ここにはmodelのinputと同じことを書く
- input: ref("my_test_raw")
# model: my_test_rawの値
rows:
- {emp_id: '3', emp_name: '山田 奈緒子'}
- {emp_id: '100', emp_name: '上田 次郎'}
- {emp_id: '9789', emp_name: '矢部 謙三'}
# expectは期待する値を定義する
expect:
# model: my_testで変換した値
rows:
- {emp_id: '0003', family_name: '山田', first_name: '奈緒子'}
- {emp_id: '0100', family_name: '上田', first_name: '次郎'}
- {emp_id: '9789', family_name: '矢部', first_name: '謙三'}
入力値の指定
givenセクションでは入力値を指定します。
- input
- ソースmodelのfromに該当する値を使用します
- rows
- テストデータを定義します
given:
# ここにはmodelのinputと同じことを書く
- input: ref("my_test_raw")
# model: my_test_rawの値
rows:
- {emp_id: '3', emp_name: '山田 奈緒子'}
- {emp_id: '100', emp_name: '上田 次郎'}
- {emp_id: '9789', emp_name: '矢部 謙三'}
期待値の指定
expectセクションではテスト結果の期待値を指定します。
- rows
- テスト対象のmodelで変換した後の値
- 今回は以下の2点を変換しています
- 社員番号→4桁0埋め
- 社員名→姓・名の項目に分割
# expectは期待する値を定義する
expect:
# model: my_testで変換した値
rows:
- {emp_id: '0003', family_name: '山田', first_name: '奈緒子'}
- {emp_id: '0100', family_name: '上田', first_name: '次郎'}
- {emp_id: '9789', family_name: '矢部', first_name: '謙三'}
テストの実行
準備ができたところでテストをやってみます!
Cloud IDEのコンソールから、以下のコマンドを実行をします。
dbt test --select my_test
エラーが出ました。
お・や・く・そ・く です。
エラーになった原因を探っていきましょう。
エラー修正
結果ログの「Details」をクリックすると、詳細なエラーメッセージが表示されます。
メッセージの最後の部分を見てみましょう。
actual differs from expected:
期待値と実際の値が異なる箇所は赤字で強調されています。
snowflakeの公式ドキュメントによると、LPADの仕様は…
LPAD(<base>, <length_expr> [, <pad>])
第1引数 | 第2引数 | 第3引数 |
---|---|---|
文字列 | 埋める桁数 | 埋める文字 |
なので、SQLで書いたlpadの引数が誤っていたことになります。
iff(len(emp_id) < 4, lpad(emp_id, '0', 4), emp_id) as emp_id,
次のように修正します。
iff(len(emp_id) < 4, lpad(emp_id, 4, '0'), emp_id) as emp_id,
もう一度testコマンドを実行してみましょう。
無事テストが成功しました!
おまけ
JoinしたModelの場合
複数のModelをJoinして新たなModelを作成するケースはよく出てきます。
select
emp.emp_id,
emp.emp_name,
emp.org_code,
org.org_name,
from
{{ ref("my_test_join_raw_emp") }} as emp
join {{ ref("my_test_join_raw_org") }} as org
on emp.org_code = org.org_code
このケースでは、testのinputを複数指定します。
version: 2
unit_tests:
- name: test_my_test_join
model:
my_test_join
# givenは入力する値を定義する
given:
# ここにはmodelのinputと同じことを書く
- input: ref("my_test_join_raw_emp")
rows:
- {emp_id: '0003', emp_name: '山田 奈緒子', org_code: '0001'}
# 複数のテーブルをJoinしたModelはinputを複数羅列する
- input: ref("my_test_join_raw_org")
rows:
- {org_code: '0001', org_name: 'マジシャン'}
# expectは期待する値を定義する
expect:
# model: my_test_joinで変換した値
rows:
- {emp_id: '0003', emp_name: '山田 奈緒子', org_code: '0001', org_name: 'マジシャン'}
参考資料
この記事を作成するにあたり、以下の資料を参考にさせていただきました。
ありがとうございます。