Pelajari prompt pembuatan tes Claude Code yang menghasilkan tes bernilai tinggi dengan menargetkan batas, invariant, dan mode kegagalan — bukan hanya jalur normal.

Suite tes yang dihasilkan otomatis sering terlihat mengesankan: puluhan tes, banyak kode setup, dan setiap nama fungsi muncul di suatu tempat. Tapi banyak dari tes itu hanyalah pemeriksaan “berfungsi ketika semuanya normal”. Mereka mudah lulus, jarang menangkap bug, dan tetap memakan waktu untuk dibaca serta dipelihara.
Dengan prompt pembuatan tes Claude Code tipikal, model cenderung mencerminkan contoh input yang dilihatnya. Anda mendapatkan variasi yang tampak berbeda tapi menutup perilaku yang sama. Hasilnya adalah suite besar dengan cakupan tipis di tempat yang penting.
Tes bernilai tinggi berbeda. Mereka adalah sekumpulan kecil yang seharusnya menangkap insiden bulan lalu. Mereka gagal ketika perilaku berubah dengan cara yang berisiko, dan tetap stabil saat refaktor yang tidak berbahaya terjadi. Satu tes bernilai tinggi bisa bernilai dua puluh pemeriksaan “mengembalikan nilai yang diharapkan”.
Generasi jalur-normal bernilai rendah biasanya punya beberapa gejala jelas:
Bayangkan sebuah fungsi yang menerapkan kode diskon. Tes jalur-normal memastikan bahwa “SAVE10” mengurangi harga. Bug nyata bersembunyi di tempat lain: harga 0 atau negatif, kode kadaluarsa, tepi pembulatan, atau batas diskon maksimum. Itulah kasus yang menyebabkan total yang salah, pelanggan marah, dan rollback tengah malam.
Tujuannya adalah beralih dari “lebih banyak tes” ke “tes yang lebih baik” dengan menargetkan tiga hal: batas (boundaries), mode kegagalan, dan invariant.
Jika Anda menginginkan unit test bernilai tinggi, berhenti meminta “lebih banyak tes” dan mulailah meminta tiga jenis spesifik ini. Ini inti dari prompt pembuatan tes Claude Code yang menghasilkan cakupan berguna alih-alih tumpukan pemeriksaan “berfungsi pada input normal”.
Batas adalah ujung apa yang diterima atau dihasilkan kode. Banyak cacat nyata adalah off-by-one, keadaan kosong, atau masalah timeout yang tidak pernah muncul di jalur normal.
Pikirkan dalam hal minimum dan maksimum (0, 1, panjang maks), kosong vs ada ("", [], nil), off-by-one (n-1, n, n+1), dan batas waktu (mendekati cutoff).
Contoh: jika sebuah API menerima “hingga 100 item”, uji 100 dan 101, bukan hanya 3.
Mode kegagalan adalah cara sistem bisa rusak: input buruk, dependensi hilang, hasil parsial, atau error hilir. Tes mode kegagalan yang baik memeriksa perilaku di bawah tekanan, bukan hanya output dalam kondisi ideal.
Contoh: ketika pemanggilan database gagal, apakah fungsi mengembalikan error yang jelas dan menghindari penulisan parsial?
Invariant adalah kebenaran yang harus tetap benar sebelum dan sesudah panggilan. Mereka mengubah kebenaran yang samar menjadi assertion yang tegas.
Contoh:
Ketika Anda fokus pada tiga target ini, Anda mendapatkan lebih sedikit tes, tetapi tiap-tiap tes membawa lebih banyak sinyal.
Jika Anda meminta tes terlalu dini, biasanya Anda mendapatkan tumpukan pemeriksaan “berfungsi seperti yang diharapkan”. Perbaikan sederhana adalah menulis kontrak kecil terlebih dahulu, lalu menghasilkan tes dari kontrak itu. Ini cara tercepat untuk mengubah prompt pembuatan tes Claude Code menjadi sesuatu yang menemukan bug nyata.
Kontrak yang berguna cukup pendek untuk dibaca dalam satu napas. Targetkan 5 sampai 10 baris yang menjawab tiga pertanyaan: apa yang masuk, apa yang keluar, dan apa lagi yang berubah.
Tulis kontrak dalam bahasa biasa, bukan kode, dan sertakan hanya apa yang bisa Anda uji.
Setelah Anda punya itu, pindai untuk tempat di mana realitas bisa merusak asumsi Anda. Itu menjadi kasus batas (min/maks, nol, overflow, string kosong, duplikat) dan mode kegagalan (timeout, permission denied, pelanggaran unique constraint, input korup).
Berikut contoh konkret untuk fitur seperti reserveInventory(itemId, qty):
Kontrak mungkin mengatakan qty harus integer positif, fungsi harus atomik, dan tidak boleh membuat stok negatif. Itu langsung menyarankan tes bernilai tinggi: qty = 0, qty = 1, qty lebih besar dari yang tersedia, panggilan konkuren, dan error database yang dipaksa setengah jalan.
Jika Anda menggunakan alat vibe-coding seperti Koder.ai, alur kerja yang sama berlaku: tulis kontrak di chat terlebih dahulu, lalu hasilkan tes yang langsung menyerang batas, mode kegagalan, dan daftar “tidak boleh terjadi”.
Gunakan prompt pembuatan tes Claude Code ini saat Anda ingin lebih sedikit tes, tapi tiap tes punya bobot. Langkah kuncinya adalah memaksa rencana tes dulu, lalu baru hasilkan kode tes setelah Anda menyetujui rencananya.
You are helping me write HIGH-SIGNAL unit tests.
Context
- Language/framework: <fill in>
- Function/module under test: <name + short description>
- Inputs: <types, ranges, constraints>
- Outputs: <types + meaning>
- Side effects/external calls: <db, network, clock, randomness>
Contract (keep it small)
1) Preconditions: <what must be true>
2) Postconditions: <what must be true after>
3) Error behavior: <how failures are surfaced>
Task
PHASE 1 (plan only, no code):
A) Propose 6-10 tests max. Do not include “happy path” unless it protects an invariant.
B) For each test, state: intent, setup, input, expected result, and WHY it is high-signal.
C) Invariants: list 3-5 invariants and how each will be asserted.
D) Boundary matrix: propose a small matrix of boundary values (min/max/empty/null/off-by-one/too-long/invalid enum).
E) Failure modes: list negative tests that prove safe behavior (no crash, no partial write, clear error).
Stop after PHASE 1 and ask for approval.
PHASE 2 (after approval):
Generate the actual test code with clear names and minimal mocks.
Trik praktis adalah meminta matriks batas sebagai tabel ringkas, sehingga celah terlihat jelas:
| Dimension | Valid edge | Just outside | “Weird” value | Expected behavior |
|---|---|---|---|---|
| length | 0 | -1 | 10,000 | error vs clamp vs accept |
Jika Claude mengusulkan 20 tes, tolak dan minta penggabungan kasus serupa serta hanya simpan yang akan menangkap bug nyata (off-by-one, tipe error salah, kehilangan data diam‑diam, invariant rusak).
Mulai dengan kontrak kecil dan konkret untuk perilaku yang Anda inginkan. Tempel signature fungsi, deskripsi singkat inputs dan outputs, dan tes yang ada (walau hanya happy-path). Ini menjaga model tetap berlabuh pada apa yang kode lakukan sebenarnya, bukan tebakan.
Selanjutnya, minta tabel risiko sebelum meminta kode tes apa pun. Wajibkan tiga kolom: kasus batas (edge input), mode kegagalan (input buruk, data hilang, timeout), dan invariant (aturan yang harus selalu benar). Tambahkan satu kalimat per baris: “kenapa ini bisa rusak.” Tabel sederhana mengungkap celah lebih cepat daripada tumpukan file tes.
Kemudian pilih set tes terkecil di mana tiap tes punya tujuan menangkap bug unik. Jika dua tes gagal karena alasan yang sama, simpan yang lebih kuat.
Aturan seleksi praktis:
Akhirnya, minta penjelasan singkat per tes: bug apa yang akan ditangkap jika tes gagal. Jika penjelasannya samar (“memvalidasi perilaku”), tes itu mungkin bernilai rendah.
Invariant adalah aturan yang harus tetap benar tak peduli input valid apa yang Anda berikan. Dengan pengujian berbasis invariant, pertama tulis aturan dalam bahasa biasa, lalu ubah menjadi assertion yang bisa gagal dengan keras.
Pilih 1 atau 2 invariant yang benar‑benar melindungi Anda dari bug nyata. Invariant yang baik sering kali tentang keselamatan (tidak ada kehilangan data), konsistensi (input sama → output sama), atau batas (tidak melebihi kap).
Tuliskan invariant sebagai kalimat pendek, lalu tentukan bukti apa yang bisa diamati oleh tes Anda: nilai kembali, data tersimpan, event yang dipancarkan, atau pemanggilan dependensi. Assertion kuat memeriksa hasil dan side effect, karena banyak bug bersembunyi di “mengembalikan OK, tapi menulis hal yang salah.”
Misalnya, fungsi yang menerapkan kupon ke pesanan:
Sekarang ubah itu menjadi assertion yang konkret:
expect(result.total).toBeGreaterThanOrEqual(0)
expect(db.getOrder(orderId).discountCents).toBe(originalDiscountCents)
Hindari assert samar seperti “mengembalikan hasil yang diharapkan”. Tegaskan aturan spesifik (non-negatif), dan efek samping spesifik (diskon tersimpan sekali).
Untuk tiap invariant, tambahkan catatan singkat di tes tentang data yang akan melanggarnya. Ini menjaga tes agar tidak meredup menjadi pemeriksaan jalur-normal.
Polanya:
Tes bernilai tinggi seringkali adalah yang mengonfirmasi kode Anda gagal dengan aman. Jika model hanya menghasilkan tes jalur-normal, Anda hampir tidak belajar apa pun tentang bagaimana fitur berperilaku ketika input dan dependensi berantakan.
Mulailah dengan memutuskan apa arti “aman” untuk fitur ini. Apakah mengembalikan error bertipe? Apakah fallback ke default? Apakah retry sekali lalu berhenti? Tuliskan perilaku yang diharapkan dalam satu kalimat, lalu buat tes yang membuktikannya.
Saat meminta Claude Code untuk tes mode kegagalan, buat tujuannya ketat: tutupi cara sistem bisa rusak, dan asert respons yang tepat. Garis bantuan yang berguna: “Lebih suka lebih sedikit tes dengan assertion lebih kuat daripada banyak tes dangkal.”
Kategori kegagalan yang sering memberi tes terbaik:
Contoh: endpoint yang membuat user dan memanggil layanan email untuk mengirim pesan sambutan. Tes jalur-normal yang rendah hanya mengecek “mengembalikan 201.” Tes mode kegagalan yang bernilai tinggi mengecek bahwa jika layanan email timeout, Anda (a) tetap membuat user dan mengembalikan 201 dengan flag “email_pending”, atau (b) mengembalikan 503 dan tidak membuat user. Pilih salah satu perilaku, lalu asert response dan side effect.
Juga uji apa yang tidak Anda bocorkan. Jika validasi gagal, pastikan tidak ada yang ditulis ke database. Jika dependensi mengembalikan payload korup, pastikan Anda tidak melempar exception yang tak tertangani atau mengembalikan stack trace mentah.
Set pengujian bernilai rendah biasanya terjadi ketika model diberi reward untuk kuantitas. Jika prompt pembuatan tes Claude Code Anda meminta “20 unit test,” Anda sering mendapatkan variasi kecil yang tampak lengkap tapi tidak menangkap apa pun yang baru.
Perangkap umum:
Contoh: fungsi “create user”. Sepuluh tes jalur-normal mungkin hanya mengubah string email dan tetap melewatkan hal penting: menolak email duplikat, menangani password kosong, dan menjamin ID user unik dan stabil.
Panduan yang membantu saat review:
Bayangkan satu fitur: menerapkan kode kupon saat checkout.
Kontrak (kecil dan dapat diuji): diberi subtotal cart dalam sen dan kupon opsional, kembalikan total akhir dalam sen. Aturan: kupon persentase dibulatkan ke bawah ke sen terdekat, kupon tetap mengurangi jumlah tetap, dan total tidak pernah di bawah 0. Kupon bisa tidak valid, kadaluarsa, atau sudah digunakan.
Jangan minta “tes untuk applyCoupon()”. Minta pengujian kasus batas, tes mode kegagalan, dan invariant yang terkait kontrak ini.
Pilih input yang cenderung merusak perhitungan atau validasi: string kupon kosong, subtotal = 0, subtotal tepat di bawah dan di atas minimal belanja, diskon tetap lebih besar dari subtotal, dan persentase seperti 33% yang menghasilkan pembulatan.
Asumsikan lookup kupon bisa gagal dan state bisa salah: layanan kupon down, kupon kadaluarsa, atau kupon sudah ditebus oleh user ini. Tes harus membuktikan apa yang terjadi selanjutnya (kupon ditolak dengan error yang jelas, total tidak berubah).
Set tes minimal bernilai tinggi (5 tes) dan apa yang masing-masing tangkap:
Jika ini lulus, Anda telah menutup titik patah umum tanpa mengisi suite dengan tes jalur-normal yang duplikat.
Sebelum menerima keluaran model, lakukan pemeriksaan kualitas cepat. Tujuannya adalah tes yang tiap‑tias melindungi Anda dari bug spesifik dan mungkin.
Gunakan daftar ini sebagai gerbang:
Trik praktis: ubah nama tes menjadi “should <perilaku> when <kondisi tepi>” dan “should not <hasil buruk> when <kegagalan>”. Jika tidak bisa mengganti nama dengan rapi, berarti tes tidak fokus.
Jika Anda membangun dengan Koder.ai, daftar ini juga cocok dengan snapshot dan rollback: hasilkan tes, jalankan, dan rollback jika set baru menambah noise tanpa meningkatkan cakupan.
Anggap prompt Anda sebagai harness yang dapat digunakan ulang, bukan permintaan sekali jalan. Simpan satu blueprint prompt (yang memaksa batas, mode kegagalan, dan invariant) dan gunakan kembali untuk setiap fungsi, endpoint, atau alur UI baru.
Kebiasaan sederhana yang meningkatkan hasil dengan cepat: minta satu kalimat per tes yang menjelaskan bug apa yang akan ditangkap. Jika kalimat itu generik, tes kemungkinan noise.
Simpan daftar invariant domain hidup untuk produk Anda. Jangan simpan dalam kepala. Tambahkan setiap kali Anda menemukan bug nyata.
Alur ringan yang bisa Anda ulang:
Jika Anda membangun aplikasi via chat, jalankan siklus ini di dalam Koder.ai (koder.ai) sehingga kontrak, rencana, dan tes yang dihasilkan hidup di satu tempat. Saat refaktor mengubah perilaku tak terduga, snapshot dan rollback memudahkan membandingkan dan mengulangi sampai set bernilai tinggi Anda tetap stabil.
Default: targetkan satu set kecil yang dapat menangkap bug nyata.
Batas sederhana yang bekerja baik adalah 6–10 tes per unit (fungsi/modul). Jika Anda membutuhkan lebih banyak, biasanya berarti unit Anda melakukan terlalu banyak atau kontrak Anda tidak jelas.
Tes happy-path kebanyakan hanya membuktikan bahwa contoh Anda masih bekerja. Mereka cenderung melewatkan hal yang rusak di produksi.
Tes bernilai tinggi menargetkan:
Mulailah dengan kontrak kecil yang bisa dibaca dalam satu napas:
Lalu hasilkan tes dari kontrak itu, bukan hanya dari contoh.
Uji ini terlebih dahulu:
Tes mode kegagalan yang baik membuktikan dua hal:
Jika ada penulisan database, selalu periksa apa yang terjadi di storage setelah kegagalan.
Pendekatan default: ubah invariant menjadi assertion pada hasil yang dapat diamati.
Contoh:
expect(total).toBeGreaterThanOrEqual(0)Layak menyimpan tes happy-path ketika ia melindungi invariant atau integrasi kritis.
Alasan bagus untuk menyimpan satu:
Jika tidak, tukarkan dengan tes batas/mode kegagalan yang menangkap lebih banyak kelas bug.
Paksa PHASE 1: rencana saja terlebih dahulu.
Minta model menyediakan:
Baru setelah Anda menyetujui rencana, minta kode. Ini mencegah keluaran “20 tes serupa”.
Default: mock hanya batas yang bukan milik Anda (DB/jaringan/clock), dan biarkan sisanya nyata.
Untuk menghindari over-mocking:
Jika tes rusak karena refactor padahal perilaku tidak berubah, seringkali itu over-mocked atau terlalu terikat implementasi.
Gunakan tes penghapusan sederhana:
Juga periksa duplikat:
Pilih satu atau dua per dimensi input sehingga tiap tes menutup risiko unik.
Lebih baik memeriksa nilai pengembalian dan side effects, karena banyak bug bersembunyi di “mengembalikan OK tapi menulis hal yang salah.”