Skip to content

Kategori CRUD Sudah Jadi, Test-nya Nol

Adityo Guni Waluyo

Fitur kategori bertingkat udah hidup tanpa satu pun test: env boot ternyata kontrak, dan edge constraint cuma bisa divalidasi lawan MySQL beneran.

Ringkasan

Awalnya fitur kategori bertingkat udah jadi tapi belum ada test sama sekali jadi kelihatan hijau palsu. Terus gue benerin TestHealthEndpoint yang gagal boot karena env belum di-set pakai Setenv plus nambah tiga test integrasi buat cek constraint hapus parent/child di MySQL asli. Testnya dikunci tag integration dan harus jalan pakai -p 1 biar nggak rebutan database barengan.

Checklist QA S5.5 tinggal satu item waktu saya buka category_repository_test.go buat pertama kali. File-nya memang baru dibuat hari itu juga. Artinya satu hal yang bikin saya berhenti sedetik: fitur kategori bertingkat, lengkap dengan create, nest, reorder, delete, udah hidup di aplikasi, dan nggak ada satu pun test yang ngawasin. Semua hijau selama ini bukan karena kode sehat, tapi karena memang nggak ada yang dites.

Tebakan pertama saya optimis sekali: tambah satu test happy path, checklist ketutup, pulang. Ternyata item pertama yang harus dibenerin malah test lama. TestHealthEndpoint udah ada, tapi servernya nggak pernah ke-start. Fungsi run() menolak boot kalau variabel DB_* dan JWT_SECRET nggak lengkap, dan test itu nggak nge-set satu pun.

Env test itu kontrak, bukan detail

Perbaikannya cuma enam baris t.Setenv yang menunjuk ke database test di port 3307, tapi pelajarannya gede: semua env yang dibaca saat boot adalah kontrak, dan test yang manggil run() wajib memenuhinya. Host dan kredensialnya diarahkan ke database test, bukan yang buat develop.

// run() refuses to start without these - point the test at the test DB
t.Setenv("DB_HOST", "<db-host>")
t.Setenv("DB_PORT", "3307")
t.Setenv("JWT_SECRET", "test-secret")

Sifat t.Setenv juga ada batasnya: dia restore nilai lama lewat Cleanup, dan karena efeknya per-proses, dilarang dipakai di test yang paralel [8]. Enam baris yang kelihatannya sepele itu tetap harus dijaga posisinya.

Tiga edge yang cuma kelihatan di MySQL beneran

Bagian inti checklist-nya bukan happy path, tapi tiga edge: hapus parent yang masih punya child, hapus kategori yang masih dipakai entitas, dan hapus id yang nggak dikenal. Dua yang pertama harus keluar ErrCategoryInUse, yang terakhir ErrCategoryNotFound. Di mock, semua skenario ini bisa saya "benarkan" sendiri, karena mock ngembaliin apa yang saya program. Justru itu titik butanya: error mapping yang disangka jelas bisa aja meleset dari perilaku MySQL asli, dan cuma test lawan database sungguhan yang bakal nemuin bedanya.

File test-nya sendiri dikunci pakai //go:build integration, jadi dia cuma ikut kalau go test dijalanin dengan -tags integration [7]. Tanpa tag itu, file-nya diabaikan builder, dan saya balik lagi ke ilusi hijau. Ini trade-off yang saya terima: test integrasi memang nggak boleh ikut lari bareng test unit tiap kali kompilasi, tapi konsekuensinya ada satu langkah sadar buat manggilnya.

-p 1: jujur soal database yang dipinjam bareng

Suite lolos, tapi cuma dengan satu flag tambahan: -p 1. Flag -p ngatur berapa test binary yang jalan paralel, default-nya GOMAXPROCS [7]. Database test kita satu dan dipakai bareng antar package, jadi pas dua package jalan bersahan, satu bisa nge-root kategori yang lagi dipakai test lain. Race-nya bukan di kode aplikasi, tapi di fixture yang mondar-mandir di tabel yang sama.

Go sebenarnya kasih kontrol granular soal test mana yang jalan dan seberapa paralel dari command line [6], jadi ini pilihan, bukan keterbatasan. Saya milih -p 1 sebagai kejujuran sementara: eksekusi lebih lambat, tapi hasilnya deterministik. Catatan di commit juga jujur, ini pre-existing yang dikejar belakangan, solusi beneran pakainya isolasi data per test.

Yang berubah dari sesi ini bukan cuma nambah empat test. Dua hal yang tadinya cuma "yakin" sekarang punya alat buat pendek: env boot itu kontrak yang tertulis di test, dan edge constraint itu klaim yang bisa dipatahkan database beneran. Checklist S5.5 ketutup dengan begitu.

Sumber

Artikel terkait