dbt

dbt Tests の全体像: 汎用テストと個別テストを正しく使い分ける

2026-04-19
NicheeLab編集部

dbt のテストは大きく2種類。YAMLで再利用可能に宣言する汎用テストと、SQLで1件ずつ不正行を返す個別テストです。

試験では「どのテストをどこに定義し、どう実行され、失敗時にどう扱うか」を押さえておくと得点源になります。実務ではコストを意識しつつ、最低限の品質保証ラインを設けるのが鍵です。

テストの基本と全体像

dbt のテストは、失敗行を返すSELECTを内部的に実行し、行が1件以上返れば失敗、0件なら成功と判定します。汎用テストはYAMLに宣言して同じパターンを複数モデル・列へ適用でき、個別テストはtests/ 以下にSQLとして作成します。

テストは通常、モデルのビルド後に dbt test で実行します。CIでは dbt build によってモデルの構築とテストが一連で行われる運用が一般的です。失敗時の挙動は severity 設定により error か warn を選べます。

  • 汎用テスト: YAMLに宣言、再利用可能、not_null/unique/accepted_values/relationships などが代表例
  • 個別テスト: tests/*.sql に定義、独自条件で不正行を抽出するSQLを書く
  • 成功条件: 不正行の件数が0件であること(原則)
  • 失敗処理: severity=error でジョブ失敗、severity=warn で警告に留める
  • 成果物: 実行結果は run_results.json に記録。必要に応じて失敗行をウェアハウスに保存(store_failures)

dbt プロジェクト内でのテスト位置付け

sources (raw)staging modelsmarts modelsgeneric testsnot_null/unique/...generic testsaccepted_values...generic testsrelationships...singular tests (tests/*.sql)任意のビジネス検証SQL

基本コマンド: モデルとテストの実行

# モデルとテストを一括
$ dbt build -s +marts.customer --fail-fast

# テストのみ、タグで絞る
$ dbt test -s tag:data_quality

# 個別テストファイルを直接指定
$ dbt test -s tests/no_future_booking.sql

汎用テスト(generic/schema)の定義と使いどころ

汎用テストは models/*.yml に宣言します。代表的な組み込みテストは not_null、unique、accepted_values、relationships です。宣言的に書けるため、保守性・再利用性に優れ、スキーマ品質の下限を素早く固められます。

独自の汎用テストは macro として定義できます。macro 名がテスト名となり、YAMLから列やモデルを引数として呼び出せます。

  • 宣言場所: schema.yml (models/sourcesなど対象のYAML)
  • 対象: モデル全体または列レベル
  • 失敗出力: 失敗行の抽出SQLが自動生成される
  • 設定例: config.severity、tags、store_failures など
観点汎用テスト(generic)個別テスト(singular)試験での覚え方
定義場所YAML (schema.yml)tests/*.sql宣言的(YAML)か命令的(SQL)か
用途整合性・制約の共通チェックビジネス特有・複合条件の検証迷ったらまず汎用で共通化
再利用性高い。多数列へ適用容易低め。ケースごとにSQL作成DRYは汎用テストで担保
可読性高い。要件がYAMLに列挙SQL次第。レビューコスト増試験は宣言的定義を重視
メンテナンスモデルリネーム時も追従しやすい依存SQLの追随が必要変更耐性は汎用が優位
実行性能単純条件が多く相対的に軽い結合や集計で重くなりやすい大規模データは汎用優先

YAML での汎用テスト定義とカスタム汎用テスト例

# models/schema.yml
version: 2
models:
  - name: customers
    columns:
      - name: customer_id
        tests:
          - not_null
          - unique
      - name: status
        tests:
          - accepted_values:
              values: ["active", "inactive"]
  - name: orders
    columns:
      - name: customer_id
        tests:
          - relationships:
              to: ref('customers')
              field: customer_id
          - not_null:
              config:
                severity: warn

# macros/tests/not_future_date.sql (カスタム汎用テスト)
{% test not_future_date(model, column_name) %}
select *
from {{ model }}
where {{ column_name }} > current_date
{% endtest %}

# 使用例 (models/payments.yml)
version: 2
models:
  - name: payments
    columns:
      - name: paid_at
        tests:
          - not_future_date

個別テスト(singular/data)の書き方と設計ポイント

個別テストは tests/ ディレクトリにSQLファイルで作成します。クエリが返す行が“失敗”です。ビジネス固有のルールや複数モデルに跨る複雑な整合性チェックを記述するのに向いています。

Jinja で ref や source を使えるため、モデルに追従する形で安全に参照できます。重い結合やウィンドウ関数を多用する場合は、対象期間の絞り込みやインデックス的なクラスタリングキーを活用してコストを抑えます。

  • 原則: 失敗行だけを返すSELECTを書く
  • 命名: tests/<機能>__<検証名>.sql などで意図を明確に
  • パフォーマンス: 期間・対象列の絞り込み、不要列の削除(select 最小化)
  • レビュー: 期待件数と境界条件(>=, > の違い)をコメントで明記

個別テストの例: 重複注文と未来日の禁止

-- tests/no_duplicate_orders.sql
with dup as (
  select order_id, count(*) as c
  from {{ ref('orders') }}
  group by 1
  having count(*) > 1
)
select * from dup

-- tests/no_future_bookings.sql
select *
from {{ ref('bookings') }}
where booking_date > current_date

実行、選択、結果の読み方(Artifacts)

dbt test は選択ルールに従って対象のテストだけを実行できます。タグ、モデル名、パスでの絞り込みが実務で便利です。CIでは変更差分だけを走らせる選択も有効です。

結果は標準出力に加えて target/run_results.json に詳細が保存されます。store_failures を有効にすると、失敗行がアダプタ依存の命名規則でウェアハウス上のテーブルに保存され、後から調査できます。

  • 選択例: dbt test -s model_name、-s path:tests/critical、-s tag:data_quality
  • 依存選択: -s +model で上流も含めて実行、@model で近傍選択
  • 高速化: --fail-fast で最初の失敗で停止
  • 成果物: run_results.json(各テストのstatus・execution_time)、manifest.json(依存関係)

選択と失敗行保存の実例

# 重要タグのみを検証
$ dbt test -s tag:critical --fail-fast

# 変更のあったモデルとそのテストのみ(例: state:modified を使う場合)
$ dbt test -s state:modified+

# プロファイル/環境で失敗行を保存
# dbt_project.yml 例
tests:
  +store_failures: true
  +severity: error

設計指針とアンチパターン

テストは「最小のコストで最大の安心」を狙います。全テーブル全列にテストを貼るのではなく、ビジネスに直結する指標・キー・外部参照から優先します。汎用テストで下限を固め、漏れたドメイン固有条件だけ個別テストで補います。

アンチパターンは、集計系モデルに対して広範囲なフルスキャン個別テストを常時回すことや、重複した検証ロジックを汎用テストと個別テストの両方に書くことです。テストの実行時間がSLAを侵食しないよう、頻度やスケジュールも設計に含めます。

  • 優先度付け: 主キー、外部キー関係、ディメンションの受け入れ値
  • 実行頻度: クリティカルは常時、重い検証は日次/週次に分離
  • 重複排除: 同一ロジックはどちらか一方に集約
  • 可観測性: 失敗件数の時系列をダッシュボード化して傾向把握

失敗を警告に留める設定例(段階的導入)

# models/core.yml
version: 2
models:
  - name: customers
    columns:
      - name: email
        tests:
          - unique:
              config:
                severity: warn  # 初期は警告で監視
          - not_null:
              config:
                severity: error # 必須はエラーで厳格に

試験対策: Analytics Engineer で問われやすい要点

試験では、汎用テストと個別テストの違い、YAML/SQLでの定義、relationships や accepted_values の意味、severity と store_failures の挙動、dbt build と dbt test の使い分けが頻出です。挙動は公式ドキュメントに準拠して覚えます。

また、ref/source を介した依存解決や、選択フラグで対象を絞る基本操作も正答率に直結します。選択記法(+/@/tag/path/state)のうち、最低限 tag と path、単純な + の意味は押さえておきましょう。

  • 汎用テストは YAML、個別テストは tests/*.sql
  • 失敗条件は「不正行が1件以上返る」
  • relationships は参照整合性チェック(子→親の存在確認)
  • accepted_values は固定リスト外を検出
  • severity=warn はジョブ継続、error は失敗終了
  • store_failures 有効時は失敗行をテーブル保存(アダプタ依存の命名)

最小セットでの暗記用スニペット

# relationships の最小例
tests:
  - relationships:
      to: ref('dim_customers')
      field: customer_id

# accepted_values の最小例
tests:
  - accepted_values:
      values: ["A", "B"]

問題で確認

Analytics Engineer

問題 1

orders テーブルの customer_id が customers テーブルの customer_id に必ず存在することを dbt の汎用テストで検証したい。最も適切な定義はどれか。

  1. models/orders.yml の customer_id に relationships テストを定義し、to: ref('customers'), field: customer_id を指定する
  2. tests/relationships_orders_customers.sql を作成し、LEFT JOIN で一致しない行を返すSQLを書く
  3. models/customers.yml に unique と not_null を付けるだけでよい
  4. models/orders.yml の customer_id に accepted_values を使い、values に全 customer_id を列挙する

正解: A

参照整合性は汎用テスト relationships を子側(orders)の対象列に宣言し、to で親モデル(ref('customers'))、field で親のキー列(customer_id)を指定して検証するのが公式かつ再利用可能な方法です。他の選択肢は実現可能性や保守性の面で不適切です。

よくある質問

dbt build と dbt test の違いは?どちらを使うべき?

dbt build はモデルの構築(run)・テスト(test)・スナップショットなどを依存順で一括実行します。CI/本番検証では build が便利です。ローカルで既存モデルに対しテストだけ回したい場合は dbt test を使います。

severity=warn は本当に失敗を無視してよいのか?

warn はジョブを失敗させませんが、run_results.json には失敗として残ります。初期導入や移行直後に有効ですが、ビジネス上クリティカルな検証は最終的に error に引き上げることを推奨します。

store_failures を有効にすると何が起きる?コスト影響は?

失敗行がウェアハウス上の専用テーブルに保存され、再調査や可視化に役立ちます。一方でテーブル作成・書き込みが増えるため、ストレージとクエリコストが上がります。重要なテストや暫定運用に限定して使うのが現実的です。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
dbt

dbt Model の基礎: SQL で定義する変換の最小単位

Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...

dbt

dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点

dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...

dbt

dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点

dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...

dbt

dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト

Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....

dbt

dbt_project.yml の読み方:主要設定と命名を最短で掴む

dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...

dbtの記事一覧 (100件)
© 2026 NicheeLab All rights reserved.