ARTICLE

dbtでデータ変換モデルを設計するときのテスト戦略

2026/9/16 (更新: 2026/9/28)

SHARE

dbtのgeneric・singular data testとunit testの役割を整理し、責任分離、検査対象の選定、失敗時の切り分けを解説。

db

dbtでデータ変換モデルを設計するときのテスト戦略

ARTICLE株式会社renue
renue

株式会社renue

2026/9/16 公開2026/9/28 更新

renueについて

renueは、AIで業務を実装する会社です

AIコンサルティングから図面AI・広告運用エージェント・コールセンターAIまで、実際に動いているサービスをご覧いただけます。renueが何をしている会社か、まずはサービス一覧からご確認ください。

dbt(data build tool) を実務で運用するチームが最初に詰まるのは「テストをどう書くか」ではなく「テストの責任範囲をどう分けるか」。generic data test と singular data test の役割や重複を整理せずに書くとテスト数が爆発し、CI が遅くなり、誰がどのテスト失敗を直すのかが曖昧になる。本記事では dbt のテスト戦略を、責任分離・運用負荷・失敗時の切り分けの3観点で整理する。

dbtには実データを検査する「data tests」と、少量の固定入力からSQLモデルの出力を検証する「unit tests(dbt v1.8以降)」がある。data testsには、ymlから指定する再利用可能なgeneric data test(旧称schema test)と、個別のSQLで書くsingular data testが含まれる。本記事では主にこの2つの書き方を使い分け、設計の落とし穴と運用ノウハウを書く。

generic data test と singular data test の使い分け

generic data test は「null性・一意性・許容値・参照整合」のようなデータに関する制約を再利用できるSQLとして定義し、ymlでモデルやカラムに適用する。列名・列型の保証には、対応するモデルでmodel contractを有効にする。dbt が標準で持つ not_null / unique / accepted_values / relationships の4種類は generic data test の中心になる。Metaplane の dbt テストベストプラクティスも参考になるが、4種すべてを全対象に機械的に当てるのではなく、各テストが確認する条件に合わせて選ぶ。

singular data test では、例えば業務ロジックに紐づく値の制約を、tests ディレクトリ配下の個別のSQLファイルに書く。同じ検査を繰り返し利用するなら、業務ルールでもgeneric data testとして定義できる。例えば「売上金額は注文行の単価×数量の合計に一致する」「クーポン適用後の値引き率は規定範囲に収まる」「キャンセル後の出荷ログは存在しない」といった、業務ルールに照らしたアサーションを記述する。data test は失敗した行を返すクエリとして書き、既定の閾値では0行なら成功と判定される。

この2つの書き方は併用できるが、generic data testの指定をymlに乱雑に増やすと、モデルのymlが肥大化して読めなくなる。singular data testのSQL本体は.sqlファイルに置く。ymlにSQLを直接書いてsingular testにする構文はなく、ymlで式を渡せるのは式を引数として受け取るgeneric test等の仕様による。 Elementary Data の dbt テストガイドでも、「テストを書きすぎるな、書く価値のあるテストを書け」という観点が繰り返し強調されている。

generic data test の粒度設計

generic data test を全カラムに書く運用は、初期コストは低く見えるが、運用に入ると負債になる。理由は2つ。第一に、主キーや結合キーは重要だが、列の意味に合わない一律の検査は誤検知を生む。非キー列でも必須入力ならnot_null、重複禁止ならuniqueが有効で、住所文字列やフリーテキストも業務要件に応じて検査する(各テストの定義)。第二に、accepted_values テストはマスター列に対しては効くが、マスターの値が増えるたびに yml を更新する手間が発生し、運用が止まる。

generic data test の粒度設計の現実解は「主キー + 結合キー + 分析で参照するディメンションを優先し、業務上重要な非キー列も対象にする」。必要に応じて、dbt のカスタム generic testでドメイン特化のチェックを書くか、Elementary や Metaplane のような外部監視ツールにデータ品質スキャンを委ねる設計が現実的。generic data testと外部監視で重複する検査を整理し、ymlの保守量とCI時間を計測しながら対象を調整する。

data test の運用設計と責任分離

data test が落ちたとき、誰が直すのかを yml の description に書く。これだけでチーム運用の停滞ポイントが1つ消える。失敗時に「データ提供元(上流ETL/ソース)の責任なのか」「dbt モデル(下流変換)の責任なのか」「テストの閾値設計(自分達)の責任なのか」が曖昧だと、チャットでの議論が長期化する。

data test を書くときの実務テンプレートは、(a) 何を保証するテストか、(b) 失敗した場合に最初に疑う原因、(c) 失敗時の連絡先、を description に1〜2文で書くこと。さらに、dbt のstore_failures: trueを設定し、失敗した行を専用テーブルに保存しておくと、原因調査の手戻りが減る。失敗行が消えてしまうと「再現できなかったので無視」になりがちで、品質が下がる。

data test の運用で見落とされやすいのが、Datafold の dbt テスト運用論でも触れられている「severity 設定」。severityの設定値はwarnまたはerrorであり、error_if・warn_ifで判定閾値を設定できる。例えば、マスターデータ不整合はerror、軽微な数値ずれはwarnとして対応期限を決める。ただし、--warn-error等で警告をエラーへ昇格させる設定がある場合、warnでも実行を失敗させるため、CI側の設定も確認する。

モデル間依存とテスト実行順序

dbt の DAG が深くなると、上流モデルのテスト失敗が下流に伝播し、原因特定に時間がかかる。実務では dbt build コマンドを使ってモデルとテストを DAG 順に実行する設計が標準になっており、上流のテストがエラーになると依存する下流リソースをスキップする仕組みが用意されている。警告にとどまる場合はこれを理由に下流を止めない。失敗の起点を追いやすくなるが、複数の原因や複数の親を持つテストでは依存関係も確認する。

CI 上では state:modified+ セレクタを使い、新規・変更リソースとその下流を選択する。比較対象には過去のmanifest.jsonが必要で、例えば dbt build --select "state:modified+" --state ./state のように保存先を指定する(公式のstateセレクタ説明)。比較用manifestは実行時に上書きされるtargetとは別に保存する。これはコードや設定の差分比較であり、入力データの変化を検出するものではない(state比較の注意点)。フルランは夜間の cron で日次に1回回し、PR の CI では差分実行に絞る。dbt の公式ベストプラクティスでも、PR ごとのフルラン運用は規模が大きくなると CI 時間が支配的になるため、差分実行への移行が推奨されている。

モデル間の依存関係を強くしすぎると、テスト失敗が連鎖して原因特定が遅れる。staging 層・intermediate 層・mart 層の3層設計を徹底し、層をまたいだ参照を最小化すると、テスト失敗が起きた層を見ればおおよその責任範囲が見える。公式ガイドは3層を基本にしつつ、組織に応じた変更と一貫した設計を認めている。保守負荷は依存関係や変更頻度にも左右され、3層から外れたことだけで指数的な増加を断定する根拠はない。

テストが詰まったときの切り分け手順

dbt test が失敗したとき、切り分け順序は次のとおり。第一にテスト自体の閾値設計を疑う。閾値の更新漏れは、コード変更や上流データ変更より発見しやすい。第二に上流データの変化を疑う。日次でデータ件数や代表値が大きく動いたら、ソース側のスキーマ変更や ETL 設定変更を確認する。第三にモデルロジックの変更を疑う。直前の PR で macro や intermediate モデルに触れたかを git log で確認する。

切り分けで最も時間を食うのは、compiled クエリを読まずにエラーメッセージだけで判断しようとする場面。target/compiled/ 配下に dbt が生成した実 SQL があるので、これを直接 BigQuery / Snowflake / Postgres に投げて値を確認するのが直接的な切り分け手段になる。compiled SQL を読む習慣がチームに根付くと、原因特定までの工数が下がる。

原因が「テスト自体の閾値設計」の場合、yml の description に閾値変更の経緯を残す。「以前の正常レンジが、キャンペーン施策の影響で新しい正常レンジに移った」のような業務文脈を残すと、半年後に同じテストで詰まったときに、再調査せずに済む。テスト yml を業務記録として運用することが、長期運用の鍵になる。

テスト数を増やしすぎないための運用ルール

dbt テストの落とし穴は、書きすぎることによるCI 遅延と保守コスト爆発。dbt データテストのパターン整理でも、テスト数を増やすほど品質が上がるわけではないという観点が指摘されている。テスト追加の判断基準は「失敗したら誰がいつ直すか」が答えられるか。答えられないテストは追加しない。

具体的なテスト追加ルール例: (a) 単一列の主キーにはnot_null + uniqueを置き、複合主キーは各構成列のnot_nullと列の組合せの一意性を検査する、(b) 外部キーは多対一なら重複を許し、relationshipsで参照整合、必須の場合はnot_nullを別途検査する、(c) 業務ルールは再利用性に応じてgenericまたはsingular data testで検査する、(d) その他の列も業務上の重要性で選び、外部監視と分担する。relationshipsはNULLを除外するため、必須性や参照先の一意性をそれだけで保証しない(公式のテスト定義、複数列の一意性検査例)。この4ルールを yml レビュー観点に組み込むと、テスト数の暴走を防げる。

dbt テスト戦略をチーム文化に落とす

dbt のテスト戦略は、技術的な書き方よりチームの運用文化に依存する。テストを書く責任、失敗を直す責任、閾値を見直す責任が誰のものかを明文化しないと、テストは「書いたきり」になり、品質保証として機能しない。dbt 導入の初期から「テスト所有者」をモデル単位で割り当てる運用にしておくと、長期運用での品質維持コストを抑えられる。

dbt の運用が長くなると、テストファイルが肥大化し、yml レビューに時間がかかるようになる。半年〜1年に一度、テスト棚卸しを入れて、使われていないテスト・閾値が古すぎるテスト・現業務に合っていないテストを削除する。テストを増やす運用だけでなく、削る運用を入れることで、テストが「資産」のまま運用される。中国語圏の dbt 運用整理でも、テストの追加と削除を半年単位で見直すというサイクル運用が紹介されており、地域を問わず長期運用での共通課題として扱われている。

AI活用のご相談はrenueへ

renueは自社開発のAIツールを自社運用する「自社実証型」AIコンサルティングファームです。

→ AIコンサルティングの詳細を見る

SHARE

FAQ

よくある質問

どちらもdata testです。genericは再利用するSQL検査をymlでモデルや列に指定し、singularは個別のSQLファイルに書きます。旧称schema testはgenericを指します。固定入力でSQLモデルのロジックを確かめるunit testや、列名・列型を保証するmodel contractとは役割が異なります。

主キー・結合キー・分析で参照するディメンションを優先し、業務上重要な非キー列も検査します。外部キーに一律のuniqueは不要で、NULLを許すかも要件で決めます。複合主キーは各構成列の非NULL性と列の組合せの一意性を確認します。重複する検査は外部監視との役割を整理し、CI時間と保守量を見て調整します。

yml descriptionに失敗時の責任者と最初に疑う原因を記載しておきます。上流ETL/dbtモデル/閾値設計のどれが原因かを切り分け、所有者がすぐ動ける状態を作ります。

CI時間が伸び、yml保守コストが爆発し、誰が直すか曖昧なテストが残ります。『失敗したら誰がいつ直すか』が答えられないテストは追加せず、半年に1回の棚卸しで削減します。

(1)テスト自体の閾値設計を疑う (2)上流データの変化を疑う (3)モデルロジック変更を疑う、の順で進めます。target/compiled/配下のSQLを直接実行して値を見るのが最も直接的です。

renueについて

renueは、AIで業務を実装する会社です

AIコンサルティングから図面AI・広告運用エージェント・コールセンターAIまで、実際に動いているサービスをご覧いただけます。renueが何をしている会社か、まずはサービス一覧からご確認ください。

関連記事

AI導入・DXの悩みをプロに相談してみませんか?

AIやDXに関する悩みがありましたら、お気軽にrenueの無料相談をご利用ください。renueのAI支援実績、コンサルティングの方針や進め方をご紹介します。

無料資料をダウンロード