データ品質のテスト

このドキュメントでは、Dataform テーブル アサーションと単体テストを使用してワークフロー コードをテストする方法について説明します。

始める前に

  1. Google Cloud コンソールで、[Dataform] ページに移動します。

    [Dataform] ページに移動

  2. リポジトリを作成または選択します。

  3. 開発ワークスペースを作成または選択します。

  4. テーブルを作成する

必要なロール

アサーションと単体テストを作成するために必要な権限を取得するには、次の IAM ロールを付与するよう管理者に依頼してください。

  • ワークスペースに対する Dataform 編集者 roles/dataform.editor
  • アサーション メタデータを Knowledge Catalog に同期するには: プロジェクトまたは @bigquery エントリ グループに対する Dataplex Catalog 編集者 roles/dataplex.catalogEditor

ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

アサーションを使用したテストデータ

アサーションは、クエリで指定された 1 つ以上の条件に違反する行を検出するデータ品質テストクエリです。クエリが行を返す場合、アサーションは失敗します。Dataform は、ワークフローを更新するたびにアサーションを実行し、アサーションが失敗した場合にアラートを送信します。

Dataform は、コンパイルされたアサーション クエリの結果を含むビューを BigQuery に自動的に作成します。ワークフロー設定ファイルで構成されているように、Dataform は、アサーションの結果を検査できるアサーション スキーマにこれらのビューを作成します。

たとえば、デフォルトの dataform_assertions スキーマの場合、Dataform は BigQuery に dataform_assertions.assertion_name という形式でビューを作成します。

すべての Dataform テーブルタイプ(テーブル、増分テーブル、ビュー、マテリアライズド ビュー)に対してアサーションを作成できます。

次の方法でアサーション値を作成できます。

組み込みアサーションを作成する

組み込みの Dataform アサーションをテーブルの config ブロックに追加できます。Dataform は、テーブルの作成後にこれらのアサーションを実行します。Dataform がテーブルを作成した後、ワークスペースの [ワークフロー実行ログ] タブでアサーションが合格したかどうかを確認できます。

テーブルの config ブロックに、次のアサーションを作成できます。

  • nonNull

    この条件は、指定された列がすべてのテーブル行で null ではないことをアサートします。この条件は、null にならない列に使用されます。

    次のサンプルコードは、テーブルの config ブロックでの nonNull アサーションを示しています。

config {
  type: "table",
  assertions: {
    nonNull: ["user_id", "customer_id", "email"]
  }
}
SELECT ...
  • rowConditions

    この条件は、すべてのテーブル行が定義したカスタム ロジックを満たすことをアサートします。各行の条件はカスタム SQL 式であり、テーブルの各行は各行の条件に対して評価されます。テーブル行が false を返す場合、アサーションは失敗します。

    次のサンプルコードは、増分テーブルの config ブロック内のカスタム rowConditions アサーションを示しています。

config {
  type: "incremental",
  assertions: {
    rowConditions: [
      'signup_date is null or signup_date > "2022-08-01"',
      'email like "%@%.%"'
    ]
  }
}
SELECT ...
  • uniqueKey

    この条件は、指定した列でテーブル行に同じ値がないことをアサートします。

    次のサンプルコードは、ビューの config ブロックでの uniqueKey アサーションを示しています。

config {
  type: "view",
  assertions: {
    uniqueKey: ["user_id"]
  }
}
SELECT ...
  • uniqueKeys

    この条件は、指定した列でテーブル行に同じ値がないことをアサートします。指定されたすべての列に同じ値を持つ行が複数あると、アサーションは失敗します。

    次のサンプルコードは、テーブルの config ブロックでの uniqueKeys アサーションを示しています。

config {
  type: "table",
  assertions: {
    uniqueKeys: [["user_id"], ["signup_date", "customer_id"]]
  }
}
SELECT ...

config ブロックにアサーションを追加する

テーブルの config ブロックにアサーションを追加する手順は次のとおりです。

  1. 開発ワークスペースの [ファイル] ペインで、テーブル定義 SQLX ファイルを選択します。
  2. テーブル ファイルの config ブロックに「assertions: {}」と入力します。
  3. assertions: {} 内にアサーションを追加します。
  4. 省略可: [書式] をクリックします。

次のコードサンプルは、config ブロックに追加された条件を示しています。

config {
  type: "table",
  assertions: {
    uniqueKey: ["user_id"],
    nonNull: ["user_id", "customer_id"],
    rowConditions: [
      'signup_date is null or signup_date > "2019-01-01"',
      'email like "%@%.%"'
    ]
  }
}
SELECT ...

SQLX を使用して手動アサーションを作成する

手動アサーションは専用の SQLX ファイルに書き込む SQL クエリです。手動アサーション SQL クエリは行を返さないようにする必要があります。クエリの実行時にクエリが行を返すと、アサーションは失敗します。

新しい SQLX ファイルに手動アサーションを追加する手順は次のとおりです。

  1. [ファイル] ペインで、definitions/ の横にある [その他] メニューをクリックします。
  2. [ファイルを作成] をクリックします。
  3. [ファイルパスを追加] フィールドに、ファイルの名前に続けて .sqlx を入力します。例: definitions/custom_assertion.sqlx

    ファイル名 には数字、英字、ハイフン、アンダースコアのみを使用できます。

  4. [ファイルを作成] をクリックします。

  5. [ファイル] パネルで、新しいファイルをクリックします。

  6. ファイルに次のように入力します。

    config {
      type: "assertion"
    }
    
  7. config ブロックの下に、SQL クエリまたは複数のクエリを記述します。

  8. 省略可: [書式] をクリックします。

次のコードサンプルは、フィールド ABcsometableNULL ではないことをアサートする SQLX ファイルでの手動アサーションを示しています。

config { type: "assertion" }

SELECT
  *
FROM
  ${ref("sometable")}
WHERE
  a IS NULL
  OR b IS NULL
  OR c IS NULL

単体テストでデータ品質をテストする

単体テストは、専用の .sqlx ファイルで定義されたデータ品質テストです。テスト対象のワークフロー アクションのすべての依存関係をモックし、想定される結果を提供します。単体テストを使用して、制御されたモック入力に対して Dataform アクションをテストし、アクション コードがエッジケース、null 値、集計、正規表現、条件付きロジックを正しく処理するかどうかを確認できます。

${ref()} 関数で参照される先行テーブル、ビュー、未加工の宣言などのアクションの依存関係のモックは、input ブロックで定義されます。各 input ブロックは、名前で依存関係を参照し、モック行を定義する SQL クエリを含んでいます。通常、このクエリは UNION ALL と組み合わせた一連の SELECT ステートメントです。期待される結果は、ワークフロー アクションの SQL ステートメントで指定された入力を実行した結果を表す SQL クエリです。

Dataform は単体テストを行ごとに実行し、ワークフロー アクションの SQL ロジックをモックデータに対して実行した実際の結果を、想定される結果セットと比較します。

単体テストは次の状態に解決されます。

  • SUCCESS: テストに合格しました。実際の結果が期待される結果と一致している。
  • FAILURE: テストに失敗しました。実際の結果が期待される結果と一致しない。

制限事項

Dataform 単体テストには次の制限があります。

  • 単体テストは、Dataform コア バージョン 3.0.56 以降で使用できます。
  • 単体テストの入力データの最大サイズは、入力あたり 100 行です。

単体テストを作成する

単体テスト用の .sqlx ファイルを definitions/ ディレクトリに保存します。definitions/ ディレクトリに新しい単体テスト .sqlx ファイルを作成する手順は次のとおりです。

  1. Google Cloud コンソールで、[Dataform] ページに移動します。

    [Dataform] ページに移動

  2. リポジトリを選択します。

  3. 開発ワークスペースを選択します。

  4. [ファイル] ペインで、definitions/ の横にある [その他] メニューをクリックします。

  5. [ファイルを作成] をクリックします。

  6. [新しいファイルを作成] ペインで、次の操作を行います。

    1. [ファイルパスを追加] フィールドにおいて、definitions/ の後で、ファイル名の後に _test.sqlx を入力します。例: definitions/customer_spend_test.sqlx

      ファイル名 には数字、英字、ハイフン、アンダースコアのみを使用できます。

    2. [ファイルを作成] をクリックします。

  7. テストファイルに次の config ブロックを追加します。

    config {
      type: "test",
      dataset: "ACTION_NAME"
    }
    

    ACTION_NAME は、このテストで検証するアクションの名前に置き換えます。

  8. テストするアクションをモックするには、アクションの依存関係ごとに input ブロックを追加し、次の形式でその依存関係をテストする SQL クエリを記述します。

    input "DEPENDENCY_NAME" {
    SELECT ...
    SELECT ...
    }
    

    DEPENDENCY_NAME は、この入力がモックするテスト済みアクションの依存関係の名前に置き換えます。

  9. input ブロックの下に、次の形式で、想定される出力行を表す標準 SQL クエリを記述します。

    -- Expected Output
    SELECT ...
    SELECT ...
    

想定される出力クエリは、モック入力が指定された場合にテスト対象のアクションが生成するはずの行と列のみを返す必要があります。

次のコードサンプルは、customer_spend.sqlx ワークフロー アクションを示しています。

config {
type: "table",
name: "customer_spend"
}

SELECT
  c.customer_id,
  c.name,
  SUM(o.amount) AS total_completed_amount
FROM
  ${ref("source_customers")} c
  JOIN
  ${ref("source_orders")} o
  ON c.customer_id = o.customer_id
WHERE
  o.status = 'COMPLETED'
GROUP BY
  1, 2

次のコードサンプルは、customer_spend.sqlx アクションの依存関係をモックし、モックの期待される結果を定義する customer_spend_test.sqlx 単体テストを示しています。

config {
  type: "test",
  dataset: "customer_spend"
}

input "source_customers" {
  SELECT 101 AS customer_id, 'Alice' AS name UNION ALL
  SELECT 102 AS customer_id, 'Bob' AS name UNION ALL
  SELECT 103 AS customer_id, 'Charlie' AS name
}

input "source_orders" {
  -- Alice has one completed and one pending order
  SELECT 1 AS order_id, 101 AS customer_id, 'COMPLETED' AS status, 100.0 AS amount UNION ALL
  SELECT 2 AS order_id, 101 AS customer_id, 'PENDING' AS status, 50.0 AS amount UNION ALL
  -- Bob has one completed order
  SELECT 3 AS order_id, 102 AS customer_id, 'COMPLETED' AS status, 250.0 AS amount UNION ALL
  -- Charlie has no orders
  SELECT 4 AS order_id, 999 AS customer_id, 'COMPLETED' AS status, 10.0 AS amount
}

-- Expected Output
SELECT 101 AS customer_id, 'Alice' AS name, 100.0 AS total_completed_amount UNION ALL
SELECT 102 AS customer_id, 'Bob' AS name, 250.0 AS total_completed_amount

単体テストを実施

単体テストを実行する手順は次のとおりです。

コンソール

  1. Google Cloud コンソールで、[Dataform] ページに移動します。

    [Dataform] ページに移動

  2. リポジトリを選択します。

  3. 開発ワークスペースを選択します。

  4. [実行を開始] > [アクションを実行] をクリックします。

  5. [実行] パネルの [実行モード] セクションで、[単体テスト] を選択します。

  6. 次のオプションのいずれかを選択します。

    • 単体テストを選択: 手動で選択した単体テストを実行します。
    • タグ付き単体テストを選択: 選択したタグの単体テストを実行します。
    • すべての単体テスト: ワークスペース内のすべての単体テストを実行します。
  7. 省略可: [実行オプション] セクションで、[優先度の高いインタラクティブ ジョブとして実行する] チェックボックスをオンにして、実行速度を優先して単体テストをすぐに実行します。

    [優先度の高いインタラクティブ ジョブとして実行する] チェックボックスをオンにしない場合、Dataform はデフォルトでバッチリソースを使用して単体テストを実行し、コンピューティング コストの削減を優先します。

  8. [実行を開始] をクリックします。

API

単体テストをプログラムで実行するには、WorkflowInvocations.create メソッドを使用してワークフロー呼び出しを作成し、invocationConfig オブジェクトに次の単体テスト実行パラメータを設定します。

"executionMode": "UNIT_TESTS_ONLY"
このパラメータを "UNIT_TESTS_ONLY" に設定すると、リポジトリで定義されている単体テストの実行がトリガーされます。
省略可: "queryPriority": "INTERACTIVE"
このパラメータが "INTERACTIVE" に設定されている場合、Dataform はクエリをすぐに実行します。設定されていない場合、Dataform はデフォルトのバッチクエリの優先度で単体テストを実行します。
省略可: "includedTargets": []
このパラメータを使用すると、単体テストを指定して、Dataform がこれらのテストのみを実行するようにできます。
省略可: "includedTags": []
: このパラメータを使用すると、タグを指定して、Dataform が指定されたタグでタグ付けされた単体テストのみを実行するようにできます。

次のコードサンプルは、デフォルトのバッチクエリの優先度で my-repo リポジトリで定義されたすべての単体テストを実行するワークフロー呼び出しの本文を示しています。

{
  "compilationResult": "projects/my-project/locations/us/repositories/my-repo/compilationResults/my-compilation-id",
  "invocationConfig": {
    "executionMode": "UNIT_TESTS_ONLY"
  }
}

次のコードサンプルは、インタラクティブ クエリの優先度で my-test 単体テストのみを実行するワークフロー呼び出しの本文を示しています。

{
  "compilationResult": "projects/my-project/locations/us/repositories/my-repo/compilationResults/my-compilation-id",
  "invocationConfig": {
    "executionMode": "UNIT_TESTS_ONLY",
    "queryPriority": "INTERACTIVE",
    "includedTargets": [
      {
        "database": "my-project",
        "schema": "my-dataset",
        "name": "my-test"
      }
    ]
  }
}

次のコードサンプルは、test-tag-1 または test-tag-2 のタグが付いた my-repo リポジトリで単体テストを実行するワークフロー呼び出しの本文を示しています。

{
  "compilationResult": "projects/my-project/locations/us/repositories/my-repo/compilationResults/my-compilation-id",
  "invocationConfig": {
    "executionMode": "UNIT_TESTS_ONLY",
    "queryPriority": "INTERACTIVE",
    "includedTags": [
      "test-tag-1",
      "test-tag-2"
    ]
  }
}

単体テストの結果を検査する

単体テストの想定スクリプトと実際のスクリプトの違いは、[コンパイル済みグラフ] または [実行] で確認できます。

コンパイル済みのグラフ

ワークフロー アクションのコンパイル済みグラフで単体テストの実際のスクリプトと想定されるスクリプトを表示する手順は次のとおりです。

  1. Google Cloud コンソールで、[Dataform] ページに移動します。

    [Dataform] ページに移動

  2. リポジトリを選択します。

  3. 開発ワークスペースを選択します。

  4. 省略可: 独立したグラフノードとしてではなく、テストするアクションにリンクされた単体テストを表示するには、workflow_settings.yaml ファイルで includeTestsInCompiledGraph 設定を true に設定します。

    1. workflow_settings.yaml ファイルを選択します。
    2. 以下のコードを追加:
    includeTestsInCompiledGraph: true
    
  5. [コンパイル済みのグラフ] をクリックします。

  6. コンパイルされたグラフで単体テストを選択し、[クエリ] をクリックします。

  7. [実際の SQL スクリプト] と [想定される SQL スクリプト] を比較します。

実行

  1. Google Cloud コンソールで、[Dataform] ページに移動します。

    [Dataform] ページに移動

  2. リポジトリを選択します。

  3. 開発ワークスペースを選択します。

  4. [実行] をクリックし、選択した単体テストの横にある [詳細を表示] をクリックします。

  5. 実際の結果のクエリ予測結果のクエリを比較します。

単体テストのベスト プラクティス

モック データセットを小さくする
コンパイルを高速化し、デバッグを容易にするため、モック入力データを 10 行未満に保ちます。
明示的な行の順序を指定する
評価中に決定論的な行順序を確保するため、アクション クエリと予想される出力クエリの両方に ORDER BY 句を必ず追加してください。
モック ステートメントで列を明示的にキャストする
モック ステートメントで列を明示的にキャストする(CAST(100 AS INT64) を使用するなど)と、型の厳密性が維持され、コンパイル エラーを防ぐことができます。
NULL または欠損値を含むテストケースを含める
入力モッククエリに NULL または欠損値を含むテストケースを含めると、COALESCE ステートメント、文字列演算、フィルタ条件で不完全な本番環境データや null 本番環境データを安全に処理できます。

次のコードサンプルは、NULL テストケースを示しています。

input "source_customers" {
  SELECT 101 AS customer_id, 'Alice' AS name UNION ALL
  SELECT 102 AS customer_id, NULL AS name -- Test null handling
}

次のステップ