Pengujian dan dokumentasi dbt

Pengujian schema dan dokumentasi yang dihasilkan dbt.

Daftar isi

Model dbt yang berhasil dibangun belum tentu benar isinya, misalnya kunci yang kembar, nilai kosong pada kolom wajib, atau status yang tidak dikenali. Topik ini membahas pengujian schema dbt, yaitu pengujian generik yang dideklarasikan pada schema.yml dengan aturan unique, not_null, accepted_values, dan relationships. Pembahasan dilanjutkan dengan situs dokumentasi yang disusun perintah dbt docs generate. Aturan yang sama dievaluasi sungguhan pada data kecil lewat simulasi DuckDB, sehingga laporan lulus dan gagalnya terlihat tanpa memasang dbt Core. Proyek yang dipakai melanjutkan proyek analitik_pesanan pada topik dasar dbt.

Pengujian schema di schema.yml#

Pengujian schema (schema test) adalah pengujian generik yang dideklarasikan per kolom pada berkas schema.yml, dan dbt mengompilasinya menjadi SELECT yang menghitung baris pelanggaran. Empat pengujian generik yang paling sering dipakai adalah unique yang menolak nilai kembar, not_null yang menolak nilai kosong, accepted_values yang menolak nilai di luar daftar, dan relationships yang menolak nilai yang tidak ditemukan pada kolom tabel acuannya. Satu deklarasi berlaku untuk seluruh baris model, tanpa perulangan yang ditulis manual.

Karena bentuknya sama, hasilnya juga seragam. Pengujian lulus bila SELECT penghitungnya tidak mengembalikan baris apa pun, dan gagal bila ada satu baris pelanggaran saja. Tabel berikut merangkum makna keempat aturan beserta contoh kelalaian yang tertangkap.

PengujianAturan yang ditegakkanKelalaian yang tertangkap
uniquenilai pada kolom tidak boleh kembarkunci baris yang ganda
not_nullnilai pada kolom wajib terisibaris tanpa kunci yang lolos muat
accepted_valuesnilai wajib termasuk daftar yang ditetapkankode baru dari sumber yang tidak diakui
relationshipsnilai wajib ada pada kolom tabel acuanrujukan yang menggantung ke baris hilang
yaml models/staging/schema.yml
version: 2

models:
  - name: stg_pesanan
    description: "Baris pesanan yang siap dipakai model lain."
    columns:
      - name: id_pesanan
        description: "Kunci pesanan dari sistem sumber."
        data_tests:
          - unique
          - not_null
      - name: id_pelanggan
        description: "Kunci pelanggan yang wajib ada di tabel acuannya."
        data_tests:
          - not_null
          - relationships:
              arguments:
                to: source('operasional', 'pelanggan')
                field: id
      - name: status
        description: "Status pesanan hasil normalisasi."
        data_tests:
          - not_null
          - accepted_values:
              arguments:
                values: ['BARU', 'SELESAI', 'DIBATALKAN']

Kolom id_pesanan diuji dengan unique sekaligus not_null karena statusnya sebagai kunci baris. Kolom id_pelanggan merujuk tabel acuan lewat pengujian relationships yang menunjuk sumber operasional.pelanggan, persis aturan konsistensi yang dihitung secara manual pada topik dimensi kualitas. Pengujian relationships sengaja melewati nilai kosong sebagaimana kunci asing pada basis data, sehingga kelalaian itu ditangkap oleh not_null yang dinyatakan pada kolom yang sama. Daftar accepted_values pada kolom status ditulis eksplisit, sehingga kode status baru dari sumber terlihat sebagai kegagalan pengujian, bukan sebagai baris yang lewat diam-diam.

Menjalankan dbt test dan simulasi aturannya#

Perintah dbt test menjalankan seluruh pengujian yang terdaftar pada proyek dan menampilkan hasilnya per pengujian. Perintah itu berakhir dengan status gagal bila ada pengujian yang merah, sehingga orkestrator yang memanggilnya dapat menghentikan tahap berikutnya. Pengujian pada satu model saja dijalankan dengan argumen --select, cara yang lazim dipakai saat satu model sedang disunting.

bash
# tidak-dijalankan
# dijalankan dari folder proyek setelah dbt Core terpasang
dbt test                       # menjalankan seluruh pengujian pada proyek
dbt test --select stg_pesanan  # menjalankan pengujian satu model saja

Keluaran perintah itu berupa daftar nama pengujian dengan penanda lulus atau gagal per barisnya, ditutup ringkasan jumlahnya. Karena dbt Core tidak terpasang pada lingkungan kerja jalur ini, laporan yang menyerupainya dihasilkan oleh simulasi berikut. Skrip uji-schema-simulasi.py menanamkan pelanggaran pada enam baris stg_pesanan, lalu menilai aturan schema.yml yang sama dengan SELECT penghitung pelanggaran pada DuckDB.

python uji-schema-simulasi.py
"""Simulasi pengujian schema dbt pada data kecil dengan DuckDB.

Aturan yang dievaluasi sama dengan schema.yml, yaitu unique, not_null,
relationships, dan accepted_values. dbt mengompilasi setiap pengujian
menjadi SELECT yang menghitung pelanggaran, dan pola yang sama dijalankan
di sini secara eksplisit agar laporan lulus-gagalnya terlihat.
"""

import duckdb

kon = duckdb.connect()

# model stg_pesanan dengan pelanggaran yang ditanamkan
kon.execute(
    """
    create table stg_pesanan as
    select * from (values
        (1, 'C01', 'BARU'),
        (2, 'C02', 'BARU'),
        (3, 'C01', 'SELESAI'),
        (3, 'C01', 'SELESAI'),
        (4, 'C99', 'DIKEMBALIKAN'),
        (5, null, 'BARU')
    ) as t(id_pesanan, id_pelanggan, status)
    """
)

# sumber acuan untuk pengujian relationships
kon.execute(
    """
    create table pelanggan as
    select * from (values ('C01'), ('C02'), ('C03')) as t(id)
    """
)

# setiap butir berupa nama pengujian di schema.yml beserta SELECT-nya
PENGUJIAN = [
    ("unique_stg_pesanan_id_pesanan",
     """
     select count(*) from (
         select id_pesanan from stg_pesanan
         group by id_pesanan having count(*) > 1
     )
     """),
    ("not_null_stg_pesanan_id_pesanan",
     "select count(*) from stg_pesanan where id_pesanan is null"),
    ("not_null_stg_pesanan_id_pelanggan",
     "select count(*) from stg_pesanan where id_pelanggan is null"),
    ("relationships_stg_pesanan_id_pelanggan",
     """
     select count(*) from stg_pesanan as s
     where s.id_pelanggan is not null
       and not exists (
           select 1 from pelanggan as p where p.id = s.id_pelanggan
       )
     """),
    ("not_null_stg_pesanan_status",
     "select count(*) from stg_pesanan where status is null"),
    ("accepted_values_stg_pesanan_status",
     """
     select count(*) from stg_pesanan
     where status is not null
       and status not in ('BARU', 'SELESAI', 'DIBATALKAN')
     """),
]

print("Simulasi pengujian schema dbt pada 6 baris stg_pesanan")
print("Aturan sama dengan schema.yml, dievaluasi sebagai SELECT penghitung pelanggaran.")
print()
jumlah_gagal = 0
for nama, sql in PENGUJIAN:
    pelanggaran = kon.execute(sql).fetchone()[0]
    status = "PASS" if pelanggaran == 0 else "FAIL"
    if pelanggaran > 0:
        jumlah_gagal += 1
    print(f"{status:<4} {nama:<40} ({pelanggaran} pelanggaran)")
print()
print(f"selesai: {len(PENGUJIAN)} pengujian, "
      f"{len(PENGUJIAN) - jumlah_gagal} lulus, {jumlah_gagal} gagal")
text Keluaran
Simulasi pengujian schema dbt pada 6 baris stg_pesanan
Aturan sama dengan schema.yml, dievaluasi sebagai SELECT penghitung pelanggaran.

FAIL unique_stg_pesanan_id_pesanan            (1 pelanggaran)
PASS not_null_stg_pesanan_id_pesanan          (0 pelanggaran)
FAIL not_null_stg_pesanan_id_pelanggan        (1 pelanggaran)
FAIL relationships_stg_pesanan_id_pelanggan   (1 pelanggaran)
PASS not_null_stg_pesanan_status              (0 pelanggaran)
FAIL accepted_values_stg_pesanan_status       (1 pelanggaran)

selesai: 6 pengujian, 2 lulus, 4 gagal

Keluaran simulasi memperlihatkan empat kegagalan yang masing-masing terikat satu aturan. Pengujian unique menangkap id 3 yang kembar, not_null menangkap id_pelanggan yang kosong, relationships menangkap C99 yang tidak ditemukan pada tabel acuan, sedangkan accepted_values menangkap status DIKEMBALIKAN yang belum terdaftar. dbt yang sesungguhnya menampilkan pesan kegagalan berisi nama pengujian dan berkas YAML asalnya, kemudian berakhir dengan status gagal, sehingga tahap berikutnya dapat dihentikan secara otomatis.

Dokumentasi yang dihasilkan dbt#

Perintah dbt docs generate menyusun situs dokumentasi dari keadaan proyek terakhir, berisi deskripsi setiap model dan kolom, konfigurasi materialisasinya, serta graf DAG yang dapat dijelajahi. Isi deskripsinya diambil dari berkas YAML yang sama dengan tempat pengujian dinyatakan, sehingga schema.yml dan sources.yml sekaligus menjadi sumber dokumentasi. Situsnya disajikan secara lokal oleh dbt docs serve dan dibuka pada browser.

bash
# tidak-dijalankan
# menyusun dokumentasi dari proyek, lalu menyajikannya secara lokal
dbt docs generate
dbt docs serve

Salah satu tampilan penting pada situs dokumentasi itu adalah graf dependensi proyek. Pada proyek analitik_pesanan yang dipakai sepanjang modul ini, DAG-nya terdiri atas satu sumber, satu model staging, dan satu model akhir, dengan pengujian schema menempel pada model staging.

DAG dependensi model pada proyek analitik_pesanansumber (source)operasional.pesananmodel (view)stg_pesananmodel (table)ringkasan_pesanansource()ref()pengujian schema (data_tests)unique, not_null, relationships,accepted_values
DAG dependensi model pada proyek analitik_pesanan

Dokumentasi yang lahir dari berkas yang sama dengan kode membuatnya tidak pernah usang. Setiap model baru yang diberi description langsung muncul pada generate berikutnya, dan setiap pengujian yang dinyatakan ikut tampak pada DAG proyeknya. Karena itu, schema.yml dipelihara sebagai berkas dokumentasi, bukan sekadar daftar aturan pengujian.

Kesalahan umum#

  1. Memperlakukan pengujian schema sebagai pengganti seluruh pengujian data. Penyebabnya, empat aturan generik mudah ditambahkan sehingga proyek terasa lengkap. Akibatnya, logika antarkolom yang keliru tetap lulus, misalnya total yang dihitung dari kolom yang salah. Perbaikannya, tambahkan pengujian singular berbentuk berkas SQL pada folder tests untuk aturan yang melibatkan lebih dari satu kolom.
  2. Membiarkan kegagalan pengujian yang berulang. Penyebabnya, aturan yang ternyata terlalu ketat tidak pernah diubah, sehingga pengujian merah menjadi pemandangan harian. Akibatnya, kegagalan baru tenggelam di antara kegagalan lama dan tidak ada yang memeriksanya. Perbaikannya, perbaiki data di sumbernya atau ubah aturannya secara sadar, lalu pastikan daftar accepted_values mengikuti nilai yang memang sah.
  3. Menulis description yang kosong pada schema.yml. Penyebabnya, pekerjaan dianggap selesai begitu aturan pengujinya tercantum. Akibatnya, situs dokumentasi memuat model tanpa penjelasan, dan pembaca dokumentasi menebak sendiri makna setiap kolomnya. Perbaikannya, isi description singkat untuk setiap model dan kolom yang diuji, sebagaimana schema.yml pada topik ini.

Ringkasan#

  • Pengujian schema dideklarasikan per kolom pada schema.yml, dan dbt mengompilasi setiap aturannya menjadi SELECT yang menghitung baris pelanggaran.
  • Perintah dbt test menampilkan laporan lulus-gagal per pengujian, dan status gagalnya dapat menghentikan tahap berikutnya pada pipeline.
  • Perintah dbt docs generate menyusun situs dokumentasi berisi deskripsi dan graf DAG yang bersumber dari berkas YAML yang sama dengan pengujian.

Referensi#