Skip to content

Tes paritas tanpa validator bersama

Adityo Guni Waluyo

Dua gerbang validasi tetap terpisah, tapi tabel uji parametrik mengikat keduanya pada kontrak accept/reject yang sama dan presedensi error yang sama.

Ringkasan

Gue kira dua modul yang errornya beda spasi harus disatuin validator biar konsisten. Ternyata import silang pas runtime dilarang, jadi yang penting bukan samanya pesan tapi samanya hasil accept atau reject lewat tabel tes parametrized. Akhirnya tanpa ubah logic runtime, cukup pakai aturan resolve dulu baru validasi dan update docs, konsistensi dibuktiin lewat tes aja.

Momen di Depan Terminal Saya sedang menatap output pytest yang merah semua di layar. Dua modul, plane-init dan plane-doc-sync, sama-sama nolak konfigurasi yang salah, tapi pesan error-nya beda persis satu spasi atau urutan katanya. Awalnya saya mikir, ini harusnya pakai validator yang sama dong biar konsisten. Saya hampir aja nge-refactor kode buat nge-extract logic validasi itu ke satu modul shared runtime. Rasanya masuk akal: kalau kodenya satu, hasilnya pasti sama.

Tebakan yang Salah dan Kontrak yang Sebenernya Ternyata, memaksakan shared runtime itu malah ngelanggar aturan arsitektur proyek ini. Cross-skill imports di runtime itu dilarang keras. Modul-modul ini emang didesain biar jalan sendiri-sendiri tanpa saling tarik dependency pas dieksekusi.

Di situlah saya sadar, yang penting itu bukan gimana mereka nolak, tapi apa yang mereka tolak. Kontraknya adalah accept/reject outcome, bukan kesamaan string pesan error. Daripada nyatuin kodenya, saya mending nyatuin tesnya. Saya ubah gate plane-init/pages jadi sebuah tabel parameterized di pytest. Dengan begitu, satu set konfigurasi adversarial yang sama persis dilewatkan ke kedua modul tersebut [2]. Pytest parametrize ini enak banget karena dukung multiple argument sets tanpa harus nulis loop testing yang berantakan. Kalo modul A nolak dan modul B juga nolak, parity-nya tercapai. Nggak peduli kalo internally mereka nge-build pesan error dengan cara yang beda.

Urutan Error Itu Ngaruh Pas nulis tabel adversarial ini, saya nemu kasus menarik. Ada satu skenario di mana path yang dikasih itu ngelanggar aturan traversal, misalnya nyoba keluar dari direktori yang diizinkan, sekaligus format file markdown-nya nggak sesuai shape yang diharuskan.

Modul pertama nge-laporin error soal shape file. Modul kedua nge-laporin error soal path traversal. Paritas gagal.

Saya sempat bingung, mana yang harusnya dicek duluan? Setelah ditelusuri, path resolution harus selesai dulu sebelum ngecek shape file. Ini masuk akal banget. Kalo kita ngecek isi atau ekstensi file sebelum yakin path-nya aman, kita ngasih celah buat sistem ngelakuin operasi baca di tempat yang nggak seharusnya. Di sini pathlib sangat ngebantu karena nyediain semantik path yang sesuai sama OS tanpa kita harus mikirin slash miring atau backslash secara manual [1]. Jadi, begitu path di-resolve dan divalidasi keamanannya, baru kita pedulikan apakah itu file yang valid atau bukan. Prinsip pages parity resolve first ini jadi aturan baku di tabel tes: traversal error selalu menang dan muncul duluan dibanding error validasi bentuk dokumen.

Dokumentasi dan Isolasi yang Tetap Terjaga Setelah tabel tesnya hijau semua, langkah selanjutnya cuma ngupdate dokumentasi scoping v3. Nggak ada perubahan logic di runtime, nggak ada import silang yang bocor. Isolasi modul tetap utuh, tapi kita punya jaminan matematis lewat tes bahwa kedua gerbang ini berperilaku identik menghadapi input yang jahat.

Pendekatan ini ngajarin saya satu hal: konsistensi nggak selalu harus dicapai dengan sentralisasi kode. Kadang, konsistensi cukup dibuktikan lewat kontrak tes yang ketat. Kita biarkan modul-modul itu tetap otonom, tapi kita ikat mereka dengan ekspektasi hasil yang sama di ujung tombak pengujian.

Sumber

Artikel terkait