Kiểm thử dữ liệu
Bạn sẽ học được
- Viết kiểm thử dữ liệu ngay trong
schema.ymlbằ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
warnvàerrorcho 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:
| Test | Câu hỏi | Dùng cho |
|---|---|---|
unique | Giá trị có trùng? | Khoá chính của mọi model |
not_null | Có dòng thiếu? | Cột bắt buộc |
accepted_values | Có giá trị lạ? | Trạng thái, loại, cờ |
relationships | Khoá 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:
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_nullChạy test:
dbt test --select stg_ordersKết quả khi dữ liệu có lỗi:
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 warningsFAIL 1 nghĩa là có một dòng vi phạm. Để xem dòng nào, thêm --store-failures:
dbt test --select stg_orders --store-failuresdbt 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:
dbt builddbt 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:
- name: status
tests:
- accepted_values:
values: ['pending', 'paid', 'shipped', 'cancelled', 'refunded']
config:
severity: warn| Mức | Hành động | Khi nào dùng |
|---|---|---|
error (mặc định) | Dừng, model phía sau không chạy | Khoá, số dòng, tiền |
warn | Chạy tiếp, in cảnh báo | Cộ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:
-- tests/assert_net_amount_khong_am.sql
select order_id, net_amount
from {{ ref('stg_orders') }}
where net_amount < 0Khô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:
dbt test --select assert_net_amount_khong_amMộ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:
-- 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) > 1Sai 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:
- Mọi khoá chính:
unique+not_null. - Mọi khoá ngoại:
relationships. - Mọi cột tiền và số lượng:
not_null, cộng singular test cho miền giá trị. - Mọi cột trạng thái:
accepted_values, thường đểwarngiai đoạn đầu. - 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
- Thêm
unique+not_nullchoorder_idcủastg_orders, chạydbt test. - 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.
- Chạy lại với
--store-failures, mở bảng audit và tìm dòng trùng. - Viết singular test cho
amount >= 0. - Đặt
severity: warnchoaccepted_valuescủastatusvà xác nhậndbt buildkhông dừng.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
| Test đạt dù dữ liệu sai | severity: warn | Đổi về error cho quy tắc bắt buộc |
| Không biết dòng nào lỗi | Không bật --store-failures | Chạy lại với cờ này và truy vấn bảng audit |
dbt run xanh nhưng mart sai | Chạy run rồi mới test | Dùng dbt build để test xen kẽ theo DAG |
| Test chạy rất lâu trên bảng lớn | Test quét toàn bộ bảng | Giớ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ại | Chạy dbt build --select stg_orders+ |
Test relationships đỏ sau khi lọc dữ liệu | Lọ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
SELECTtrả về dòng sai; 0 dòng là đạt. - Bốn test dựng sẵn:
unique,not_null,accepted_values,relationships. dbt buildchạy test xen kẽ theo DAG, chặn dữ liệu sai trước khi lan sang mart.--store-failuresbiế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