Test Impact Analysis adalah teknik untuk memilih subset test yang paling relevan berdasarkan perubahan kode, sehingga pipeline CI tidak selalu harus menjalankan seluruh test suite. Tujuannya bukan sekadar menghemat menit build, tetapi mempercepat feedback tanpa menurunkan kepercayaan terhadap hasil rilis.

Pendekatan ini cocok ketika test suite mulai besar, monorepo makin kompleks, atau satu perubahan kecil memicu pipeline panjang yang tidak proporsional. Kuncinya adalah pemilihan test yang terukur: memakai data perubahan file, dependency graph, mapping modul-ke-test, lalu tetap menyediakan fallback full run untuk menjaga akurasi dan mencegah blind spot.

Apa itu Test Impact Analysis dan bagaimana bedanya dengan full test suite?

Pada pendekatan tradisional, setiap pull request atau commit menjalankan semua test: unit, integration, contract, end-to-end, dan seterusnya. Ini sederhana dan aman, tetapi sering tidak efisien. Mengubah satu helper kecil di satu service bisa tetap memicu ribuan test di area yang tidak terkait.

Dengan Test Impact Analysis, CI menganalisis perubahan lalu menentukan test mana yang mungkin terdampak. Contohnya:

  • Perubahan pada modul autentikasi menjalankan unit test autentikasi, integration test service login, dan contract test endpoint terkait.
  • Perubahan dokumentasi atau file non-runtime bisa melewati sebagian besar test, mungkin hanya lint atau validation tertentu.
  • Perubahan library bersama di monorepo dapat memperluas cakupan ke semua consumer yang bergantung pada library tersebut.

Perbedaan utama dengan full test suite ada pada strategi seleksi:

  • Full suite: semua test selalu dijalankan.
  • TIA: hanya test relevan dijalankan di jalur utama CI, biasanya disertai mekanisme pengaman seperti smoke test wajib dan full run terjadwal.

Ini penting: TIA bukan pengganti total untuk full suite. Ia adalah optimisasi eksekusi pada jalur CI harian, bukan alasan untuk menghapus validasi menyeluruh.

Kapan Test Impact Analysis cocok dipakai?

TIA paling cocok ketika biaya menjalankan semua test mulai menghambat delivery, tetapi tim masih membutuhkan sinyal kualitas yang cepat. Beberapa kondisi yang umum:

  • Monorepo dengan banyak package, service, atau aplikasi yang saling bergantung.
  • Backend service dengan test integration cukup berat, misalnya melibatkan database, message broker, atau external stub.
  • CI paralel terbatas, sehingga durasi total pipeline sulit ditekan hanya dengan menambah worker.
  • Frekuensi commit tinggi, sehingga antrean CI menjadi bottleneck.
  • Test suite heterogen, di mana sebagian besar perubahan sebenarnya hanya menyentuh area kecil.

TIA kurang cocok jika:

  • Basis test masih kecil dan full run sudah cepat.
  • Dependency antar modul tidak jelas atau sering berubah tanpa dokumentasi.
  • Banyak test flaky, sehingga hasil seleksi sulit dipercaya.
  • Tim belum punya disiplin dasar seperti ownership test, naming yang konsisten, dan smoke test inti.

Jika full suite masih cukup cepat, biasanya lebih baik mempertahankan kesederhanaan. TIA menambah kompleksitas operasional, jadi manfaatnya harus jelas.

Input utama yang dipakai oleh Test Impact Analysis

Akurasi TIA bergantung pada kualitas sinyal yang dipakai untuk memilih test. Umumnya ada empat input utama.

1. Perubahan file

Ini adalah input paling dasar: file apa saja yang berubah antara base branch dan commit saat ini. Sumbernya biasanya dari diff Git.

git diff --name-only origin/main...HEAD

Contoh interpretasi sederhana:

  • docs/ berubah -> tidak memicu test aplikasi.
  • services/billing/ berubah -> jalankan test billing.
  • packages/shared-auth/ berubah -> jalankan test package itu dan semua consumer yang bergantung padanya.

Kelebihannya mudah diimplementasikan. Kekurangannya, pendekatan berbasis path saja sering terlalu kasar. Perubahan di library bersama bisa berdampak luas, tetapi tidak terlihat hanya dari path test target.

2. Dependency graph

Dependency graph memetakan hubungan antar modul, package, service, atau komponen. Dengan graph ini, perubahan pada satu node dapat ditelusuri ke semua downstream consumer.

Contoh kasus di monorepo:

  • packages/core-config dipakai oleh service-a, service-b, dan worker-c.
  • Jika core-config berubah, maka TIA tidak cukup hanya menjalankan test package tersebut; test untuk consumer terkait juga perlu dipertimbangkan.

Dependency graph bisa dibangun dari:

  • manifest dependency proyek,
  • import analysis statis,
  • build graph internal,
  • metadata package atau module boundary.

Semakin akurat graph-nya, semakin kecil risiko test penting terlewat.

3. Mapping modul-ke-test

Ini adalah jembatan antara perubahan kode dan daftar test aktual yang harus dijalankan. Mapping dapat dibuat dengan beberapa cara:

  • Konvensi direktori: test di folder tertentu diasosiasikan ke modul tertentu.
  • Metadata manual: file konfigurasi yang mendefinisikan modul X diproteksi oleh test A, B, C.
  • Data runtime: rekam file atau modul apa yang disentuh saat test berjalan, lalu bangun peta relasi secara historis.

Pendekatan manual mudah dimulai, tetapi rawan basi. Pendekatan runtime lebih akurat, tetapi perlu infrastruktur pengumpulan data dan mekanisme pembaruan.

4. Fallback full run

Fallback adalah pengaman ketika seleksi test tidak cukup yakin. Ini bisa dipicu oleh kondisi seperti:

  • perubahan pada area inti seperti framework glue code, dependency injection, config global, migration, atau code generation,
  • dependency graph tidak lengkap,
  • mapping test belum tersedia untuk modul tertentu,
  • perubahan terlalu luas atau menyentuh banyak boundary.

Tanpa fallback, TIA mudah berubah dari optimisasi menjadi sumber false negative.

Workflow implementasi bertahap di monorepo atau backend service

Implementasi yang aman sebaiknya bertahap. Jangan langsung mengandalkan TIA untuk menentukan kelulusan pipeline produksi tanpa fase validasi.

Tahap 1: Mulai dari path-based rules

Langkah awal yang paling praktis adalah membuat aturan berbasis direktori. Misalnya di monorepo:

changed files -> impacted areas -> tests to run
services/payments/**      -> run: test:payments, integration:payments
services/orders/**        -> run: test:orders
packages/shared-logging/** -> run: test:shared-logging + consumers
schema/**                 -> run: contract-tests + integration-tests
infra/**                  -> run: smoke-tests + selective service tests

Untuk backend service tunggal, bentuknya bisa lebih sederhana:

  • ubah file di src/auth/ -> jalankan unit test auth, integration test login/session, smoke test API utama;
  • ubah file di db/migrations/ -> paksa full integration run;
  • ubah file di README.md -> lewati test aplikasi, tetap jalankan lint docs jika ada.

Pada tahap ini, tujuan utama bukan presisi maksimal, tetapi membangun fondasi dan melihat potensi penghematan.

Tahap 2: Tambahkan dependency graph

Setelah aturan path stabil, tambahkan propagasi dampak berdasarkan graph dependensi. Ini sangat berguna di monorepo.

Alur sederhananya:

  1. Ambil daftar file yang berubah.
  2. Petakan file ke modul pemilik.
  3. Telusuri semua downstream consumer pada dependency graph.
  4. Gabungkan test dari modul yang berubah dan consumer terdampak.
  5. Tambahkan smoke test wajib.
  6. Jika aturan aman tidak terpenuhi, fallback ke full run.

Secara konseptual, pseudocode-nya seperti ini:

changed_files = git_diff(base, head)
changed_modules = resolve_modules(changed_files)
impacted_modules = closure_of_dependents(changed_modules, dependency_graph)
selected_tests = tests_for_modules(impacted_modules)
selected_tests += mandatory_smoke_tests

if touches_global_config(changed_files) or missing_mapping(impacted_modules):
    selected_tests = full_test_suite

Kenapa ini bekerja? Karena dampak perubahan tidak berhenti pada file yang diubah, tetapi merambat melalui relasi konsumsi kode.

Tahap 3: Bangun mapping modul-ke-test yang lebih akurat

Setelah dua tahap awal, bottleneck berikutnya biasanya adalah akurasi. Terlalu banyak test ikut terpilih berarti CI belum cukup cepat; terlalu sedikit berarti risiko false negative naik.

Pilihan praktis:

  • Static ownership map: setiap modul memiliki daftar test package/suite yang wajib dijalankan.
  • Historical execution map: simpan hasil observasi test mana yang menyentuh modul mana berdasarkan eksekusi sebelumnya.
  • Hybrid: manual untuk area kritis, otomatis untuk area lain.

Pendekatan hybrid sering paling realistis karena area seperti autentikasi, pembayaran, otorisasi, dan migrasi database biasanya memerlukan aturan eksplisit.

Tahap 4: Terapkan mode shadow sebelum enforcement penuh

Sebelum TIA benar-benar menentukan status lulus/gagal CI utama, jalankan dalam shadow mode:

  • TIA memilih subset test.
  • CI tetap menjalankan full suite pada pipeline pembanding atau pada sampel commit tertentu.
  • Bandingkan apakah TIA pernah melewatkan test yang seharusnya gagal.

Ini cara paling aman untuk mengukur akurasi sebelum adopsi penuh.

Contoh aturan seleksi test yang masuk akal

Aturan seleksi yang baik harus dapat dipahami tim, mudah diaudit, dan punya fallback jelas. Contoh rule set untuk monorepo:

rules:
  - if_changed: ["docs/**", "**/*.md"]
    run: ["lint:docs"]

  - if_changed: ["packages/ui/**"]
    run: ["test:ui", "smoke:web"]

  - if_changed: ["services/auth/**"]
    run: ["test:auth", "integration:auth", "smoke:api"]

  - if_changed: ["packages/shared/**"]
    run: ["test:shared", "dependents-of:packages/shared", "smoke:api"]

  - if_changed: ["db/migrations/**", "config/**", "infra/**"]
    run: ["full:integration", "smoke:api"]
    force_full_run: true

Hal yang perlu diperhatikan:

  • Area berisiko tinggi sebaiknya konservatif. Jangan terlalu agresif mengurangi test pada auth, billing, permission, data migration, atau serialization boundary.
  • Smoke test wajib sebaiknya selalu dijalankan walaupun perubahan terlihat kecil.
  • Rule precedence harus jelas. Jika dua aturan bentrok, pilih yang lebih aman.

Strategi validasi akurasi Test Impact Analysis

TIA hanya berguna jika tingkat kepercayaannya terukur. Validasi akurasi harus menjadi bagian dari implementasi, bukan pekerjaan belakangan.

1. Bandingkan TIA vs full run

Pada periode awal, untuk sebagian commit atau pada jadwal tertentu:

  • jalankan subset test hasil TIA,
  • jalankan full suite sebagai pembanding,
  • catat apakah ada kegagalan yang hanya muncul di full suite.

Kasus seperti itu adalah sinyal bahwa mapping atau dependency graph belum lengkap.

2. Ukur false negative secara eksplisit

Risiko utama TIA adalah false negative: CI terlihat hijau karena test penting tidak dijalankan, padahal perubahan sebenarnya merusak sistem. Ini jauh lebih berbahaya daripada false positive.

Beberapa sumber false negative yang umum:

  • dependency graph tidak menangkap relasi runtime atau refleksi,
  • test mapping basi setelah refactor,
  • perubahan config global tidak dianggap berdampak luas,
  • generated code atau schema change tidak masuk analisis,
  • shared fixture atau helper test berubah tetapi tidak dipetakan ke suite yang relevan.

3. Lakukan sampling konservatif

Jika belum yakin, gunakan strategi seperti:

  • persentase commit acak tetap menjalankan full suite,
  • semua merge ke branch utama menjalankan validasi yang lebih luas daripada pull request biasa,
  • release candidate selalu menjalankan full suite.

Sampling membantu mendeteksi blind spot tanpa langsung mengembalikan biaya CI ke level awal.

4. Audit area yang sering lolos seleksi

Jika ada modul yang hampir tidak pernah memicu test tertentu, periksa apakah memang benar tidak relevan atau ada gap pada aturan. TIA yang terlalu hemat sering terlihat dari distribusi eksekusi test yang tidak wajar.

Metrik yang perlu dipantau

Tanpa metrik, sulit menilai apakah TIA benar-benar membantu. Fokus pada metrik operasional dan kualitas, bukan hanya durasi pipeline.

  • Median dan p95 durasi CI: melihat dampak ke pengalaman developer, bukan hanya rata-rata.
  • Jumlah test yang dijalankan per perubahan: indikator efisiensi seleksi.
  • Hit rate fallback full run: jika terlalu sering, aturan terlalu konservatif atau mapping belum matang.
  • Mismatch rate TIA vs full run: berapa kali full suite menemukan masalah yang tidak ditangkap subset TIA.
  • Failure detection latency: seberapa cepat bug terdeteksi setelah commit masuk.
  • Flaky test rate: test flaky akan mengacaukan evaluasi efektivitas TIA.
  • Distribusi area coverage: modul kritis mana yang jarang tersentuh validasi.

Interpretasi metrik juga penting. Misalnya durasi CI turun tajam tetapi mismatch rate naik, berarti optimisasi terlalu agresif.

Pencegahan regresi agar kepercayaan rilis tetap tinggi

Test Impact Analysis yang sehat selalu dipasangkan dengan lapisan pengaman. Tujuannya agar percepatan CI tidak dibayar dengan turunnya kualitas rilis.

Nightly full test

Jalankan full suite secara terjadwal, misalnya nightly atau beberapa kali per hari tergantung kebutuhan tim. Ini berguna untuk:

  • menangkap gap pada aturan seleksi,
  • mendeteksi regresi lintas modul yang tidak terlihat pada commit tunggal,
  • memverifikasi kesehatan keseluruhan suite.

Nightly full run bukan pengganti CI per-commit, tetapi safety net yang penting.

Smoke test wajib

Walaupun TIA memilih test yang sempit, tetap jalankan smoke test inti pada setiap perubahan atau minimal pada setiap merge. Contohnya:

  • aplikasi bisa start,
  • endpoint health atau route utama merespons,
  • alur login dasar berjalan,
  • database migration check atau schema compatibility dasar lolos.

Smoke test membantu menangkap kerusakan kasar yang tidak selalu tampak dari mapping granular.

Quarantine untuk flaky test

Flaky test harus dipisahkan dari sinyal utama. Jika tidak, Anda akan sulit membedakan apakah kegagalan berasal dari seleksi TIA yang salah atau test yang memang tidak stabil.

Praktik yang umum:

  • beri label test flaky,
  • keluarkan dari gating utama jika perlu,
  • tetap jalankan di jalur terpisah dan buat backlog perbaikannya,
  • jangan biarkan quarantine menjadi tempat permanen.

Tujuan quarantine bukan menyembunyikan masalah, tetapi menjaga kualitas sinyal sambil memperbaiki akar penyebab.

Audit coverage area berisiko

Area seperti autentikasi, otorisasi, pembayaran, persistence, schema evolution, concurrency, dan boundary API perlu audit berkala. Tanyakan:

  • apakah perubahan di area ini selalu memicu test yang cukup?
  • apakah ada jalur runtime penting yang tidak tercermin di dependency graph?
  • apakah smoke test dan integration test untuk area ini memadai?

Jika jawabannya meragukan, pilih aturan yang lebih konservatif.

Trade-off dan keterbatasan yang perlu dipahami

TIA bukan gratis. Ada biaya implementasi dan biaya pemeliharaan.

  • Kompleksitas operasional meningkat: Anda perlu graph, mapping, observability, dan audit aturan.
  • Akurasi tidak pernah sempurna: terutama pada sistem dengan dynamic loading, refleksi, code generation, atau dependency runtime yang sulit dianalisis statis.
  • Refactor besar dapat merusak mapping: setiap perubahan struktur kode perlu diikuti pembaruan aturan atau regenerasi data.
  • Optimisasi berlebihan berbahaya: mengurangi terlalu banyak test sering baru terasa saat bug lolos ke lingkungan lebih lanjut.

Karena itu, desain TIA yang baik lebih mengutamakan keamanan seleksi daripada penghematan maksimum.

Debugging tips saat hasil TIA terasa tidak masuk akal

  • Periksa diff input: pastikan file yang berubah benar-benar terbaca, termasuk generated file atau perubahan rename.
  • Audit ownership mapping: apakah file dipetakan ke modul yang tepat setelah refactor?
  • Verifikasi dependency graph: apakah downstream consumer yang relevan ikut terhitung?
  • Cek global trigger: config, schema, env template, dan shared test utilities sering perlu aturan khusus.
  • Bandingkan dengan full run: identifikasi test gagal yang tidak dipilih, lalu telusuri gap pemetaan.
  • Lihat histori flaky: jangan salah menyimpulkan kelemahan TIA jika penyebabnya test tidak stabil.

Checklist adopsi Test Impact Analysis

Jika ingin mengadopsi Test Impact Analysis untuk CI lebih cepat tanpa mengurangi cakupan, gunakan checklist berikut:

  • Full suite saat ini memang cukup mahal dan menjadi bottleneck.
  • Tim tahu area kritis yang harus selalu diperlakukan konservatif.
  • Ada cara andal untuk membaca perubahan file dari VCS.
  • Modul atau package boundary cukup jelas.
  • Dependency graph tersedia atau bisa dibangun bertahap.
  • Sudah ada smoke test inti yang stabil.
  • Ada mekanisme fallback full run.
  • TIA diuji dalam shadow mode sebelum dijadikan gating utama.
  • Nightly full run dijadwalkan.
  • Flaky test ditangani dengan quarantine dan perbaikan terencana.
  • Metrik mismatch, durasi CI, dan fallback rate dipantau rutin.
  • Audit berkala dilakukan untuk area berisiko tinggi.

Penutup

Test Impact Analysis adalah pendekatan praktis untuk mempercepat CI ketika full test suite sudah terlalu mahal dijalankan pada setiap perubahan. Nilai utamanya bukan sekadar mengurangi jumlah test, tetapi memilih test yang paling relevan secara terukur sambil mempertahankan mekanisme pengaman seperti smoke test wajib, fallback full run, dan nightly full suite.

Jika diterapkan bertahap, divalidasi dengan pembanding, dan dipantau lewat metrik yang tepat, TIA dapat memberi feedback lebih cepat tanpa mengorbankan kepercayaan rilis. Namun jika aturan seleksi tidak diaudit dan area berisiko diperlakukan terlalu agresif, manfaat performa bisa dengan mudah berubah menjadi false negative yang mahal.