Implementasi palsu wajib gagal: menguji selftest sendiri
Suite hijau semua belum tentu bagus. Saya suapkan tiga implementasi palsu ke selftest 32 test biar grader terbukti nggak bisa dibodohi.
Ringkasan
Suite test hijau semua bisa bohong, soalnya validator yang isinya cuma exit 0 tetap lolos tanpa ngetes apa-apa. Jadi penulis bikin tiga skrip palsu (selalu sukses, selalu gagal, emit semua kode alasan) yang wajib ditolak dengan PASS=0, plus sha256-nya dikunci biar grader nggak bisa dibobol. Ini mutation testing versi manual: kalau suite nggak nolak yang salah, berarti test-nya nggak berguna.
Yang bikin curiga justru suite yang hijau semua
Layar terminal nunjukin angka yang seharusnya bikin senang: 32 test di ingest-blueprint-selftest.sh hijau semua, PASS=32 FAIL=0. Sehari sebelumnya saya baru publish artikel soal 32 test merah yang dibekukan sebagai kontrak CLI. Nah sekarang implementasinya nyusul dan semua test lolos. Eh, tapi di kepala saya malah muncul pertanyaan nggak enak: gimana kalau 32 test ini lolos tapi nggak membuktikan apa-apa?
Asumsi awal saya: suite hijau berarti aman. Logikanya memang kedengeran masuk akal, test lewat berarti fitur jalan. Tapi coba pikirin skenario ini: bagaimana kalau validator-nya isinya cuma exit 0 di semua kondisi? Semua test tetap hijau. Suite kayak gini namanya vakum, alias lolos tanpa ngetes apa-apa.
Ilusi ini bukan sekadar teori. FAQ resmi coverage.py jelasin bahwa baris definisi fungsi atau kelas itu tereksekusi saat modul di-import, jadi sebuah modul bisa nunjukin coverage moderat padahal nol test beneran jalan [3]. Ned Batchelder sebagai maintainer-nya juga bilang langsgung: coverage itu bagus tapi nggak sempurna [3]. Angka hijau di dashboard belum tentu cermin kualitas.
Tiga palsu yang wajib dihajar habis
Commit c609608 di repo internal saya adalah jawabannya. Selftest 32 test itu di-refreeze dengan tiga penjaga baru. Caranya: saya bikin tiga implementasi palsu dengan perilaku ekstrem, terus saya suapkan ke suite.
- FAKE-OK. Selalu keluar dengan kode sukses 0, pura-pura semua validasi lolos.
- FAKE-FAIL. Selalu gagal total tanpa proses apa pun.
- FAKE-ALLREASONS. Yang paling licik: selalu memuntahkan semua kode alasan kegagalan yang dikenal validator.
Bar penerimaannya ketat banget: masing-masing palsu wajib mendapat skor tepat PASS=0 dan FAIL=32. Satu aja lolos berarti suite-nya vakum. FAKE-ALLREASONS penting karena pola agar yang sering terjadi: validator cuma ngecek "ada string error", bukan "string error-nya yang bener". Makanya sekarang test juga ngesertakan kode alasan secara exact. Gagal karena R75 beda artinya dengan gagal karena R80b, dan test saya wajib bisa bedain.
Ada satu penjaga lagi. File selftest ini nyematkan sha256-nya sendiri di pesan commit, diawali 8100450c. Skenario terburuknya: seseorang ngubah grader biar selalu lolos biar proses verifikasi cepat selesai. Tanpa hash terkunci, suite tetap hijau dan nggak ada yang sadar penjahatnya ada di dalam. Dengan hash, tiap edit diam-diam di grader langsung ketahuan. Baseline setelah refreeze: STUB=32 melawan stub, terus kernel suite PASS=74 FAIL=0 STUB=0.
Nama resminya mutation testing
Yang saya lakukan ini sebenernya versi manual dari prinsip mutation testing. Dokumentasi resmi Stryker Mutator ngejelasin konsepnya: sengaja masukin perubahan (mutan) ke kode, terus test dijalankan. Yang diharapkan justru test-nya gagal. Kalau nggak ada test yang gagal, itu tanda test-nya kurang kuat [1]. Mutan yang lolos disebut surviving mutants, dan tiap survivor adalah test yang hilang [1].
Alat otomatis kayak Stryker buat JavaScript atau mutmut buat Python memang kerjanya rapi, nyari-nyari operator yang bisa dibalik terus ngetes ulang [1][2]. Tapi buat project CLI bash yang kecil, saya milih jalan manual. Tiga skrip palsu, bar PASS=0 x3, hash terkunci. Saya lebih seneng tahu pasti grader saya nggak bisa dibodohi skrip yang selalu sukses, daripada ngejar angka coverage 100 persen yang semu. Bukti bahwa sistem bisa nolak hal yang salah akhirnya lebih nyata daripada sekadar meloloskan hal yang bener.
Kalo kamu mau nyoba sendiri: bikin satu skrip bash yang isinya cuma exit 0, suapkan ke suite kamu, dan jalankan. Suite yang sehat wajib nolaknya. Kalau dia masih hijau, kamu baru aja nemuin masalah yang lebih serius daripada bug biasa.
Sources
[1] Stryker Mutator, What is mutation testing?
[2] mutmut, Python mutation tester documentation
[3] Ned Batchelder, coverage.py FAQ