DHDataHọc
Lý thuyếtBài 2/85 phút đọc+10 XP

Kiểm thử dữ liệu

Bạn sẽ học được

  • Viết kiểm thử dữ liệu ngay trong schema.yml bằng bốn test dựng sẵn.
  • Hiểu vì sao một test trong dbt chỉ là câu SQL trả về các dòng sai.
  • Đặt mức warn và error cho từng test.
  • Lưu lại các dòng lỗi để điều tra bằng --store-failures.
  • Viết một singular test cho quy tắc riêng của doanh nghiệp.

Khái niệm cốt lõi

Một model chạy thành công chỉ chứng minh câu SQL không lỗi cú pháp. Nó không chứng minh order_id không trùng, không chứng minh amount không âm, không chứng minh customer_id có tồn tại trong bảng khách hàng.

dbt đưa kiểm thử vào cùng chỗ với model: khai báo trong schema.yml, chạy bằng một lệnh, và chặn các model phía sau nếu dữ liệu hỏng.

Mỗi test trong dbt là một câu SELECT. Nếu câu đó trả về ít nhất một dòng, test thất bại. Không dòng nào nghĩa là đạt.

Cách thiết kế này rất mạnh vì bạn không cần học API riêng: muốn kiểm tra quy tắc gì, viết câu SQL trả về các bản ghi vi phạm quy tắc đó.

Bốn test dựng sẵn phủ phần lớn nhu cầu:

TestCâu hỏiDùng cho
uniqueGiá trị có trùng?Khoá chính của mọi model
not_nullCó dòng thiếu?Cột bắt buộc
accepted_valuesCó giá trị lạ?Trạng thái, loại, cờ
relationshipsKhoá ngoại có mồ côi?Cột tham chiếu bảng khác

Ví dụ chạy được

Khai báo test trong models/staging/schema.yml:

code
version: 2

models:
  - name: stg_orders
    description: "Đơn hàng đã làm sạch, một dòng cho mỗi order_id."
    columns:
      - name: order_id
        tests:
          - unique
          - not_null
      - name: customer_id
        tests:
          - not_null
          - relationships:
              to: ref('stg_customers')
              field: customer_id
      - name: status
        tests:
          - accepted_values:
              values: ['pending', 'paid', 'shipped', 'cancelled', 'refunded']
      - name: net_amount
        tests:
          - not_null

Chạy test:

code
dbt test --select stg_orders

Kết quả khi dữ liệu có lỗi:

code
1 of 5 PASS unique_stg_orders_order_id ....................... [PASS in 0.31s]
2 of 5 PASS not_null_stg_orders_order_id ..................... [PASS in 0.28s]
3 of 5 FAIL 1 relationships_stg_orders_customer_id ........... [FAIL 1 in 0.44s]
4 of 5 PASS accepted_values_stg_orders_status ................ [PASS in 0.35s]
5 of 5 PASS not_null_stg_orders_net_amount ................... [PASS in 0.30s]
Completed with 1 error and 0 warnings

FAIL 1 nghĩa là có một dòng vi phạm. Để xem dòng nào, thêm --store-failures:

code
dbt test --select stg_orders --store-failures

dbt tạo bảng dbt_test__audit.relationships_stg_orders_customer_id chứa đúng bản ghi lỗi. Truy vấn bảng đó là bước tiếp theo, không phải đoán.

Chạy tất cả trong một lệnh:

code
dbt build

dbt build chạy model và test xen kẽ theo DAG: stg_orders chạy → test của nó chạy → nếu đạt mới chạy fct_orders. Đây là điểm khác biệt quan trọng so với dbt run && dbt test, khi cả hai chạy xong mới phát hiện lỗi và bảng mart đã bị ghi sai.

Mức độ nghiêm trọng

Không phải test nào cũng nên chặn pipeline:

code
      - name: status
        tests:
          - accepted_values:
              values: ['pending', 'paid', 'shipped', 'cancelled', 'refunded']
              config:
                severity: warn
MứcHành độngKhi nào dùng
error (mặc định)Dừng, model phía sau không chạyKhoá, số dòng, tiền
warnChạy tiếp, in cảnh báoCột phụ, dữ liệu đang mở rộng

Một giá trị mới như 'returned' có thể là hợp lệ và chỉ cần cập nhật danh sách. Nhưng order_id trùng thì không bao giờ chấp nhận được.

Singular test

Quy tắc doanh nghiệp không có trong bốn test dựng sẵn thì viết file trong tests/. Tên file bắt đầu bằng assert_ hoặc nội dung rõ ràng:

code
-- tests/assert_net_amount_khong_am.sql
select order_id, net_amount
from {{ ref('stg_orders') }}
where net_amount < 0

Không có SELECT bọc ngoài, không có expect. Chỉ cần câu trả về các dòng sai. Chạy:

code
dbt test --select assert_net_amount_khong_am

Một ví dụ khác — kiểm tra tổng doanh thu của mart khớp với staging trong cùng ngày:

code
-- tests/assert_doanh_thu_khop.sql
with mart as (
    select sum(revenue) as tong from {{ ref('fct_orders') }}
    where order_date = current_date - 1
),
stg as (
    select sum(net_amount) as tong from {{ ref('stg_orders') }}
    where order_date = current_date - 1
)
select m.tong as mart, s.tong as staging
from mart m cross join stg s
where abs(m.tong - s.tong) > 1

Sai lệch 1 đồng được bỏ qua vì làm tròn; sai lệch lớn hơn nghĩa là phép join trong mart đang nhân bản dòng.

Bao nhiêu test là đủ

Không cần test mọi cột. Nguyên tắc thực dụng:

  1. Mọi khoá chính: unique + not_null.
  2. Mọi khoá ngoại: relationships.
  3. Mọi cột tiền và số lượng: not_null, cộng singular test cho miền giá trị.
  4. Mọi cột trạng thái: accepted_values, thường để warn giai đoạn đầu.
  5. Một vài test tổng hợp ở tầng mart: tổng khớp, không âm, không vượt ngưỡng.

Test là hợp đồng với người dùng dữ liệu. Mỗi test bạn viết là một lỗi bạn không phải phát hiện qua báo cáo sai của sếp.

Thực hành

  1. Thêm unique + not_null cho order_id của stg_orders, chạy dbt test.
  2. Cố tình chèn một dòng trùng trong bảng nguồn, chạy lại và đọc thông báo lỗi.
  3. Chạy lại với --store-failures, mở bảng audit và tìm dòng trùng.
  4. Viết singular test cho amount >= 0.
  5. Đặt severity: warn cho accepted_values của status và xác nhận dbt build không dừng.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
Test đạt dù dữ liệu saiseverity: warnĐổi về error cho quy tắc bắt buộc
Không biết dòng nào lỗiKhông bật --store-failuresChạy lại với cờ này và truy vấn bảng audit
dbt run xanh nhưng mart saiChạy run rồi mới testDùng dbt build để test xen kẽ theo DAG
Test chạy rất lâu trên bảng lớnTest quét toàn bộ bảngGiới hạn theo ngày trong singular test
Sửa dữ liệu nguồn nhưng test vẫn đỏChạy trên model cũ chưa build lạiChạy dbt build --select stg_orders+
Test relationships đỏ sau khi lọc dữ liệuLọc bỏ khách hàng nhưng giữ đơnĐảm bảo hai model cùng phạm vi lọc

Tóm tắt

  • Test trong dbt là câu SELECT trả về dòng sai; 0 dòng là đạt.
  • Bốn test dựng sẵn: unique, not_null, accepted_values, relationships.
  • dbt build chạy test xen kẽ theo DAG, chặn dữ liệu sai trước khi lan sang mart.
  • --store-failures biến thông báo lỗi thành bảng có thể truy vấn.
  • Singular test dành cho quy tắc riêng của doanh nghiệp.

Dùng ← → để chuyển bài