實施測試策略

已完成

測試是可靠資料工程解決方案的關鍵基礎。 當你實施 全面的測試策略時,能及早發現問題、驗證假設,並確保你的流程提供一致且值得信賴的結果。 隨著資料量增加及管線複雜化, 自動化測試 成為維持品質與降低生產失敗風險的關鍵。

在本單元中,您將學習如何實作涵蓋 單元測試、 整合測試、 端對端測試及 Azure Databricks 使用者 驗收測試(UAT) 的測試策略。

了解考試金字塔

設計良好的測試策略遵循 測試金字塔 的概念。 在基礎上,你會有許多快速且孤立的單元測試。 往上看,驗證元件互動的整合測試較少。 在最上層,您會有少量完整的端對端測試與 UAT 案例。

測試金字塔圖示。

此結構存在是因為不同測試類型有不同的目的:

測試類型 目標 Scope 速度
單元測試 確認各項功能是否正常運作 單一函式或類別 速度快(毫秒級)
整合測試 驗證元件能一起運作 多重組成部分 中等 (秒)
端對端測試 確認完整的工作流程是否產生預期成果 完整管線 較慢(分鐘)
UAT 確保解決方案符合業務需求 商務案例 不定

從單元測試開始,你能建立對程式碼基本建構元素的信心。 整合測試則確認這些區塊是否正確連接。 端對端測試驗證整個系統是否能產生正確的結果。 UAT 確保利害關係人在正式部署前批准解決方案。

用 pytest 實作單元測試

單元測試著重於單獨測試 個別功能。 在 Azure Databricks 中, pytest 框架提供了強大的方法來撰寫並執行 Python 程式碼的單元測試。

考慮一個資料轉換函數,依國家/地區篩選紀錄:

def filter_country_region(df, country_region="USA"):
    return df[df.iso_code == country_region]

要測試此函式,請建立一個遵循 pytest 命名慣例的測試檔案。 檔案應以以下字母開頭test_或結尾:_test.py

import pytest
import pandas as pd
from transforms import filter_country_region

@pytest.fixture
def sample_data():
    """Create test data that mimics production structure."""
    return pd.DataFrame({
        'iso_code': ['USA', 'USA', 'CAN', 'GBR'],
        'value': [100, 200, 150, 175]
    })

def test_filter_country_region_default(sample_data):
    result = filter_country_region(sample_data)
    assert len(result) == 2
    assert all(result.iso_code == 'USA')

def test_filter_country_region_specific(sample_data):
    result = filter_country_region(sample_data, country_region='CAN')
    assert len(result) == 1
    assert result.iloc[0]['value'] == 150

裝飾者會 @pytest.fixture 產生 可重複使用的測試資料。 此方法透過使用與實際資料結構鏡像的 合成資料集 ,保護生產資料,且不會暴露敏感資訊。

要在 Databricks 筆記本中執行這些測試,請安裝 pytest 並執行:

%pip install pytest

import pytest
retcode = pytest.main([".", "-v", "-p", "no:cacheprovider"])
assert retcode == 0, "Tests failed. Check the output above."

小提示

設計函式以回傳可預測的單一類型輸出。 一個會回傳資料框或 False 的函數會變得難以測試。 相反地,讓它總是回傳一個 DataFrame,即使是空的。

設計整合測試

整合測試會驗證 多個元件是否正確協同運作 。 在資料管線中,這些測試確認資料在擷取、轉換與儲存階段間的正常流動。

與使用模擬資料的單元測試不同,整合測試通常針對 實際的 Databricks 資源執行。 你可以從測試表讀取,套用轉換,並驗證輸出格式:

def test_pipeline_integration(spark):
    """Test that transformation pipeline produces expected schema."""
    # Read from test table
    input_df = spark.sql("SELECT * FROM test_catalog.test_schema.raw_data")
    
    # Apply transformation pipeline
    result_df = transform_pipeline(input_df)
    
    # Verify output structure
    expected_columns = ['id', 'processed_date', 'category', 'amount']
    assert result_df.columns == expected_columns
    
    # Verify data types
    assert result_df.schema['amount'].dataType.simpleString() == 'decimal(10,2)'

整合測試比單元測試需要更多的設定。 建立 專門的測試架構或目錄 ,包含具代表性的資料樣本。 這種隔離性防止測試影響生產資料,同時驗證真實元件互動。

這很重要

切勿對生產資料表執行整合測試。 建立獨立的測試環境,資料與生產結構相似,但不包含敏感資訊。

建立端對端測試

端到端測試模擬從頭到尾 的完整工作流程 。 這些測試驗證了整個流程在給予特定輸入時是否能產生預期結果。

設計端對端測試以涵蓋 真實情境:

def test_daily_processing_pipeline():
    """Validate complete daily data processing workflow."""
    # Setup: Create test input files
    test_date = "2024-01-15"
    setup_test_input_files(test_date)
    
    # Execute: Run the complete pipeline
    run_daily_pipeline(test_date)
    
    # Verify: Check final output table
    result = spark.sql(f"""
        SELECT COUNT(*) as row_count, 
               SUM(amount) as total_amount
        FROM production.daily_summary
        WHERE process_date = '{test_date}'
    """)
    
    row = result.first()
    assert row.row_count == 1000, f"Expected 1000 rows, got {row.row_count}"
    assert abs(row.total_amount - 50000.00) < 0.01
    
    # Cleanup: Remove test data
    cleanup_test_data(test_date)

端對端測試的執行時間比單元測試或整合測試更長。 安排它們在 非尖峰時段 執行,或作為部署流程的一部分,而不是在每次程式碼變更時執行。

計劃進行使用者驗收測試

使用者接受測試(UAT)涉及 利害關係人驗證 您的解決方案是否符合 業務需求。 過去的測試類型著重於技術正確性,UAT 則確認該解決方案能帶來商業價值。

有效的UAT需要謹慎規劃:

  • 在開發開始前,與利害關係人定義接受標準
  • 打造一個與製作相符的舞台環境
  • 準備反映實際商業應用情境的測試情境
  • 記錄每種情境的預期結果
  • 建立回報問題的回饋流程

UAT 通常在暫 存環境中 運行,讓業務用戶可以利用真實資料與解決方案互動。 考慮建立筆記本,讓利害關係人能執行以驗證特定情境:

# UAT Scenario: Monthly revenue reconciliation
# Expected outcome: Total matches finance system within 1%

finance_total = 1_250_000.00  # From finance system

pipeline_result = spark.sql("""
    SELECT SUM(revenue) as total_revenue
    FROM reporting.monthly_revenue
    WHERE month = '2024-01'
""").first()

variance = abs(pipeline_result.total_revenue - finance_total) / finance_total
print(f"Variance: {variance:.2%}")

if variance < 0.01:
    print("✓ UAT PASSED: Revenue totals match within tolerance")
else:
    print("✗ UAT FAILED: Revenue variance exceeds 1% threshold")

組織你的測驗結構

組織良好的測試結構能讓測試更易於維護與執行。 請遵循以下 Azure Databricks 專案的慣例:

project/
├── src/
│   └── transforms.py
├── tests/
│   ├── unit/
│   │   └── test_transforms.py
│   ├── integration/
│   │   └── test_pipeline.py
│   └── e2e/
│       └── test_daily_workflow.py
├── notebooks/
│   └── run_tests.py
└── requirements.txt

Databricks 建議在 Python 專案中將函式及其單元測試存放 在筆記本之外 。 此方法能改善 程式碼重用 ,並使測試更為直接。 把函式存放在 .py Git 資料夾的檔案中,並視需要匯入筆記本。

執行測試時,請建立專用筆記本執行 pytest:

%pip install -r ../requirements.txt

import pytest
import sys

# Prevent pytest from caching to readonly filesystem
sys.dont_write_bytecode = True

# Run all tests with verbose output
retcode = pytest.main([
    "tests/",
    "-v",
    "-p", "no:cacheprovider"
])

assert retcode == 0, "Test suite failed"

在將更改部署到生產環境之前,透過建立一個 Databricks 工作來運行您的測試筆記本,以自動化測試執行。 此自動化確保程式碼變更不會引發迴歸。