測試資料品質

本文說明如何使用 Dataform 表格斷言和單元測試,測試工作流程程式碼。

事前準備

  1. 前往 Google Cloud 控制台的「Dataform」頁面。

    前往「Dataform」頁面

  2. 選取或建立存放區

  3. 選取或建立開發工作區

  4. 建立資料表

必要的角色

如要取得建立斷言和單元測試所需的權限,請要求管理員授予您下列 IAM 角色:

如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

使用斷言測試資料

斷言是資料品質測試查詢,可找出違反查詢中一或多項條件的資料列。如果查詢傳回任何資料列,斷言就會失敗。Dataform 會在每次更新工作流程時執行斷言,並在任何斷言失敗時發出快訊。

Dataform 會自動在 BigQuery 中建立檢視區塊,其中包含已編譯的斷言查詢結果。如工作流程設定檔中所設定,Dataform 會在斷言結構定義中建立這些檢視區塊,方便您檢查斷言結果。

舉例來說,如果是預設的 dataform_assertions 結構定義,Dataform 會在 BigQuery 中建立檢視區塊,格式如下:dataform_assertions.assertion_name

您可以為所有 Dataform 資料表類型建立斷言:資料表、遞增資料表、檢視區塊和具體化檢視區塊。

您可以透過下列方式建立斷言:

建立內建斷言

您可以將內建的 Dataform 斷言新增至資料表的 config 區塊。Dataform 會在建立資料表後執行這些判斷。Dataform 建立資料表後,您可以在工作區的「工作流程執行記錄」分頁中,查看斷言是否通過。

您可以在表格的 config 區塊中建立下列判斷:

  • nonNull

    這項條件會斷言指定資料欄在所有資料表列中都不是空值。這個條件適用於絕不會是 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 區塊中新增斷言

如要將斷言新增至資料表的設定區塊,請按照下列步驟操作:

  1. 在開發工作區的「Files」窗格中,選取資料表定義 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. 在「Add a file path」(新增檔案路徑) 欄位中,輸入檔案名稱,然後輸入 .sqlx。例如:definitions/custom_assertion.sqlx

    檔案名稱只能包含數字、英文字母、連字號和底線。

  4. 點選「建立檔案」

  5. 在「檔案」窗格中,按一下新檔案。

  6. 在檔案中輸入:

    config {
      type: "assertion"
    }
    
  7. config 區塊下方,撰寫 SQL 查詢或多個查詢。

  8. 選用:按一下「格式」

下列程式碼範例顯示 SQLX 檔案中的手動判斷提示,可判斷欄位 ABcsometable 中絕不會是 NULL

config { type: "assertion" }

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

使用單元測試測試資料品質

單元測試是資料品質測試,定義於專屬的 .sqlx 檔案中,會模擬受測工作流程動作的所有依附元件,並提供預期結果。您可以針對受控模擬輸入內容測試 Dataform 動作,確認動作程式碼是否能正確處理極端情況、空值、彙整、規則運算式和條件式邏輯。

動作依附元件的模擬 (例如前置工作表、檢視區塊或 ${ref()} 函式中參照的原始宣告) 會在 input 區塊中定義。每個 input 區塊都會依名稱參照依附元件,並包含定義模擬資料列的 SQL 查詢。這項查詢通常是一系列 SELECT 陳述式,並與 UNION ALL 結合。預期結果是 SQL 查詢,代表對工作流程動作 SQL 陳述式執行指定輸入內容的結果。

Dataform 會逐列執行單元測試,並比較對模擬資料執行工作流程動作的 SQL 邏輯後得到的實際結果,與預期結果集。

單元測試會解析為下列狀態:

  • SUCCESS:測試已通過。實際結果符合預期結果。
  • FAILURE:測試失敗。實際結果與預期結果不符。

限制

Dataform 單元測試有下列限制:

  • 單元測試適用於 Dataform Core 3.0.56 以上版本。
  • 單元測試的輸入資料大小上限為每項輸入 100 列。

建立單元測試

將單元測試的 .sqlx 檔案儲存在 definitions/ 目錄中。 如要在 definitions/ 目錄中建立新的單元測試 .sqlx 檔案,請按照下列步驟操作:

  1. 前往 Google Cloud 控制台的「Dataform」頁面。

    前往「Dataform」頁面

  2. 選取存放區。

  3. 選取開發工作區。

  4. 在「檔案」窗格中,點按 definitions/ 旁的「更多」選單。

  5. 點選「建立檔案」

  6. 在「建立新檔案」窗格中,執行下列步驟:

    1. 在「Add a file path」(新增檔案路徑) 欄位中,輸入 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_test.sqlx 單元測試,該測試會模擬 customer_spend.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. 依序點選「Start execution」(開始執行) >「Execute actions」(執行動作)

  5. 在「Execute」面板的「Execution mode」部分,選取「Unit tests」

  6. 選取下列選項之一:

    • 選取單元測試:執行您手動選取的單元測試。
    • 選取已標記的單元測試:執行具有所選標記的單元測試。
    • 所有單元測試:執行工作區中的所有單元測試。
  7. 選用步驟:在「執行選項」部分,選取「以高優先順序執行互動式工作」核取方塊,立即執行單元測試,優先考量執行速度。

    如果未勾選「以高優先順序執行互動式工作」核取方塊,Dataform 預設會使用批次資源執行單元測試,優先節省運算費用。

  8. 按一下「Start execution」(開始執行)

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-1test-tag-2my-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 測試案例:

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

後續步驟