Penjelasan mutation testing
Spec: ISO/IEC/IEEE 29119-4 ISO/IEC/IEEE 29119-4 Spec: PHPUnit PHPUnit Evidence: Test-backed
Gambaran umum
Bagian berjudul “Gambaran umum”Cakupan baris memberi tahu Anda bahwa suatu baris dijalankan saat suite pengujian berjalan. Cakupan baris tidak memberi tahu apakah ada pengujian yang akan gagal jika baris itu salah. Mutation testing menutup celah itu dengan merusak kode secara sengaja dan memeriksa apakah pengujian menyadarinya. Halaman ini menjelaskan arti sebuah mutation score dan bagaimana NextPDF menggunakannya sebagai alat diagnostik, bukan sebagai piala.
Mengapa ini penting
Bagian berjudul “Mengapa ini penting”Cakupan adalah salah satu metrik pengujian yang paling dipercaya, sekaligus salah satu yang paling menyesatkan. Pengujian yang memanggil sebuah metode tetapi tidak melakukan asersi apa pun tetap menjalankan setiap baris di dalamnya: cakupan sempurna, deteksi nol. Literatur standar menyatakan secara tegas bahwa urutan di antara kriteria cakupan tidak memberi indikasi apa pun tentang kemampuannya mengungkap kesalahan. Kemampuan itu adalah properti yang disebut sebagai efektivitas pengujian (ISO/IEC/IEEE 29119-4, §C.2.4). Persentase cakupan dan jaminan menemukan kesalahan adalah dua klaim yang berbeda.
Bagi sebuah mesin PDF, hal ini bukan sekadar teori. Pemeriksaan byte-range tanda tangan, offset cross-reference, cabang pengodean — pengujian bisa “mencakup” semua ini sepenuhnya tanpa pernah mengasersi nilai yang penting. Suite yang hijau di atas fondasi pengujian yang lemah lebih buruk daripada celah yang jujur, karena justru membuat orang enggan memeriksa lebih lanjut.
Versi singkatnya
Bagian berjudul “Versi singkatnya”- Mutation testing menghasilkan ribuan suntingan kecil yang disengaja (mutant) pada kode sumber — mengubah
<menjadi<=,+menjadi-, atau nilaireturn— lalu menjalankan ulang pengujian terhadap masing-masing mutant. - Jika sebuah pengujian gagal pada suatu mutant, mutant itu terbunuh: ada pengujian yang benar-benar mengasersi perilaku tersebut. Jika setiap pengujian tetap lolos, mutant itu lolos: perilakunya dijalankan tetapi tidak pernah diperiksa.
- Mutation Score Indicator (MSI) secara kasar adalah jumlah mutant yang terbunuh dibagi total mutant yang tidak ekuivalen. MSI mengukur apakah pengujian Anda mendeteksi perubahan, bukan apakah pengujian itu menjalankan kode.
- Sebagian mutant bersifat ekuivalen — mutant tersebut tidak dapat mengubah perilaku yang dapat diamati, sehingga tidak ada pengujian yang dapat membunuhnya. Menghitung mutant semacam ini sebagai kegagalan tidaklah jujur. NextPDF membuktikan dan mencatatnya dalam ledger alih-alih mengabaikannya secara informal.
- NextPDF menggunakan MSI untuk menemukan dan memperkuat pengujian yang lemah. Ini adalah gerbang diagnostik dalam continuous integration, bukan angka pemasaran.
Bagaimana NextPDF menanganinya
Bagian berjudul “Bagaimana NextPDF menanganinya”Mutasi dijalankan pada mesin dengan mutator Infection. Mutator ini dikonfigurasi untuk pohon kode sumber produksi, dengan keluarga mutator aritmetika, boolean, batas-kondisi, kesetaraan, nilai-balik, dan penghapusan diaktifkan — persis operator yang mengungkap logika yang “dijalankan tetapi tidak diasersi”. Alurnya mekanis:
- Start green The suite must pass before mutation begins.
- Mutate Apply one small, deliberate change to the source.
- Re-run Run the tests that cover the mutated line.
- Killed A test failed — the behaviour is genuinely asserted.
- Escaped All tests still pass — a weak spot to strengthen.
- Equivalent No test can kill it because behaviour is unchanged — proven and ledgered, not scored as a miss.
Dua keputusan desain membuat angka ini layak dipercaya. Pertama, skor ini dijadikan sebuah gerbang. Continuous integration menegakkan MSI minimum (dan covered-MSI minimum) serta menjalankan varian bercakupan-diff pada baris yang berubah. Akibatnya, perubahan yang menambahkan kode tanpa asersi nyata akan tertangkap saat peninjauan, bukan baru ditemukan kemudian. Kedua, NextPDF tidak diam-diam mengabaikan mutant yang merepotkan. Mutant yang benar-benar ekuivalen secara semantik — misalnya !== versus != ketika strict typing menjamin kedua operan memiliki tipe yang sama — dicatat dalam sebuah mutation ledger dengan pengujian bukti ekuivalensi yang eksplisit. Akibatnya, jumlah mutant yang lolos mencerminkan celah yang nyata, bukan pembukuan semata. PHPStan Level 10 ditambah strict_types serta properti bertipe itulah yang membuat bukti ekuivalensi tersebut sahih.
Apa kata buktinya
Bagian berjudul “Apa kata buktinya”Evidence: Test-backed Mutation testing dikonfigurasi pada mesin untuk direktori kode sumber produksi dengan keluarga mutator pengungkap perilaku diaktifkan. Konfigurasi ini ditegakkan sebagai gerbang continuous-integration dengan MSI minimum dan varian bercakupan-diff. Ini adalah pemeriksaan build, bukan pertimbangan belakangan.
Evidence: Test-backed Masalah mutant-ekuivalen ditangani secara jujur. Mutant yang ekuivalen secara semantik diklasifikasikan dan didukung oleh pengujian bukti-ekuivalensi khusus dalam sebuah mutation ledger, dengan kesahihan setiap bukti bertumpu pada PHPStan Level 10 ditambah strict typing. Karena itu, jumlah mutant yang lolos mewakili perilaku tak-terdeteksi yang nyata, bukan derau tak-terbunuh yang dilebih-lebihkan hingga membuat skor tampak lebih buruk.
Evidence: Standard-backed Mutasi adalah teknik yang diakui, bukan ciptaan NextPDF. Spec: ISO/IEC/IEEE 29119-4, §B.2.4 ISO/IEC/IEEE 29119-4 §B.2.4 menjelaskan penerapan mutasi generik pada elemen-elemen sebuah spesifikasi untuk menurunkan mutasi spesifik untuk pengujian. Teknik ini diperlukan karena standar yang sama menyatakan bahwa relasi subsumes dari kriteria cakupan tidak mengurutkannya berdasarkan kemampuan mengungkap kesalahan (ISO/IEC/IEEE 29119-4, §C.2.4).
Evidence: Standard-backed Cakupan itu sendiri terdefinisi dengan baik dan terbatas. Spec: PHPUnit PHPUnit membedakan cakupan baris, cabang, dan jalur. Cakupan baris hanya mencatat bahwa sebuah baris yang dapat dieksekusi dijalankan. Memahami definisinya itulah yang membuat ketidakcukupannya menjadi jelas.
Contoh praktis
Bagian berjudul “Contoh praktis”Yang penting bukanlah perintahnya — melainkan apa yang diberitahukan oleh sebuah mutant yang lolos:
<?php
declare(strict_types=1);
final class ByteRange{ // Suppose the production guard is: // if ($offset < 0) { throw new InvalidByteRange(); } public function assertNonNegative(int $offset): void { if ($offset < 0) { throw new InvalidByteRange('offset must be >= 0'); } }}
// A test that EXECUTES this line but does not assert the boundary:// $byteRange->assertNonNegative(5); // no exception expected, none asserted// gives 100% line coverage of assertNonNegative().//// Mutation flips `< 0` to `<= 0`. Behaviour now differs ONLY at $offset === 0.// If no test passes 0 and asserts what happens, every test still passes:// the mutant ESCAPED. Coverage said "tested"; mutation said "the boundary// is unasserted". The fix is a test that pins offset === 0, not a higher// target.//// composer mutation:diff → mutate only changed lines, enforce min MSI// composer mutation:full → full-tree mutation gateDi situlah letak nilai mutant yang lolos. Ia menemukan asersi yang nyata, spesifik, dan hilang yang oleh laporan cakupan dinilai telah diuji sepenuhnya.
Kesalahpahaman umum
Bagian berjudul “Kesalahpahaman umum”Kesalahpahaman utamanya adalah bahwa mutation score merupakan nilai yang harus dimaksimalkan. MSI yang sangat tinggi yang dicapai dengan menulis pengujian untuk membunuh mutant sama hampanya dengan cakupan tinggi yang dicapai dengan memanggil metode tanpa melakukan asersi. Metrik itu telah dimanipulasi dan tidak lagi mengukur deteksi. NextPDF menggunakan MSI untuk menemukan pengujian yang lemah. Hasil yang diharapkan adalah asersi yang lebih baik; berbangga dengan angka jelas bukan tujuannya.
Kesalahpahaman kedua adalah bahwa setiap mutant yang bertahan merupakan cacat pada pengujian. Sebagian mutant benar-benar ekuivalen dan tidak dapat dibunuh oleh pengujian mana pun, karena tidak mengubah perilaku yang dapat diamati. Memperlakukan mutant semacam itu sebagai kegagalan menghasilkan skor yang tidak jujur dan rendah secara artifisial, serta mendorong orang untuk mengabaikan laporan tersebut. Jawaban NextPDF adalah membuktikan ekuivalensi secara eksplisit dan mencatatnya dalam ledger, bukan diam-diam menyembunyikannya atau berpura-pura angkanya lebih buruk daripada yang sebenarnya.
Batasan dan ruang lingkup
Bagian berjudul “Batasan dan ruang lingkup”Mutation testing mengukur apakah pengujian mendeteksi perubahan yang disuntikkan. Ini tidak membuktikan bahwa kode itu benar. Ini tidak mengukur performa atau kesesuaian. Ini tidak dapat membunuh mutant yang benar-benar ekuivalen. Mutation score saat ini, ambang batas MSI-minimum yang berlaku, jumlah mutant ekuivalen yang tercatat dalam ledger, dan angka cakupan apa pun merupakan sinyal kualitas yang hidup, yang dihasilkan dari artefak continuous-integration dan dipublikasikan bersama build. Angka-angka itu sengaja tidak dicantumkan di sini, karena angka yang ditempelkan ke dalam prosa akan usang dan menjadi kebohongan kecil. Satu-satunya fakta stabil yang dinyatakan halaman ini adalah PHPStan Level 10, dan itu adalah properti konfigurasi yang menjadi landasan bukti ekuivalensi, bukan sebuah pengukuran.
Pemilihan mutator, ambang batas, dan kebijakan ledger dikelola oleh konfigurasi mutasi mesin dan dapat berkembang. Konfigurasi itulah yang menjadi otoritas jika suatu saat bertentangan dengan halaman ini. Tidak ada klaim apa pun yang dibuat di sini mengenai efektivitas pengujian pustaka lain mana pun.
Dokumen terkait
Bagian berjudul “Dokumen terkait”- Piramida pengujian NextPDF — lima tingkatan pengujian yang diaudit oleh mutation testing untuk deteksi kesalahan yang nyata.
- Strict types, di mana-mana — bagaimana PHPStan Level 10 dan strict typing membuat bukti mutant-ekuivalen menjadi sahih.
- Golden-file testing — tingkatan lain yang daya deteksinya divalidasi dengan bantuan mutation testing.
Glosarium
Bagian berjudul “Glosarium”- Mutant — satu perubahan kecil yang sengaja dilakukan pada kode sumber, digunakan untuk menguji apakah suite pengujian akan menyadari perubahan tersebut.
- Mutant terbunuh — mutant yang membuat setidaknya satu pengujian gagal; perilakunya benar-benar diasersi.
- Mutant lolos — mutant yang membuat setiap pengujian tetap lolos. Perilakunya dijalankan tetapi tidak pernah diasersi — sebuah titik lemah yang harus diperbaiki.
- Mutant ekuivalen — mutant yang tidak dapat mengubah perilaku yang dapat diamati, sehingga tidak ada pengujian yang dapat membunuhnya. NextPDF membuktikan dan mencatatnya dalam ledger.
- MSI (Mutation Score Indicator) — secara kasar, mutant yang terbunuh dibagi total mutant yang tidak ekuivalen; sebuah ukuran deteksi, bukan eksekusi.
- Cakupan baris — metrik yang hanya mencatat bahwa sebuah baris yang dapat dieksekusi dijalankan selama suite berjalan; didefinisikan oleh PHPUnit, dan tidak memadai jika berdiri sendiri.