Test-Driven Development (TDD) dalam Praktik dengan Astro
Terbit
Test-driven development (TDD) artinya menulis test sebelum menulis kode. Saya membangun situs ini dengan TDD, memakai Vitest dan Astro. Tulisan ini menjelaskan cara kerja TDD, cara saya menyiapkannya, dan bug nyata yang tertangkap sebelum sampai ke pengunjung.
Poin penting
- TDD adalah siklus sederhana: tulis test yang gagal, buat test itu lulus, lalu rapikan kodenya.
- TDD juga cocok untuk proyek kecil. Situs pribadi saya ternyata punya banyak bagian: dua bahasa, CMS, dan halaman yang dibuat otomatis untuk setiap tag dan teknologi.
- Test yang paling berguna adalah test yang memeriksa situs yang sudah jadi, bukan hanya fungsi satu per satu.
- Test yang langsung lulus di percobaan pertama patut dicurigai. Pastikan Anda melihatnya gagal dulu.
Apa itu test-driven development?
TDD adalah cara menulis kode dalam tiga langkah pendek. Langkah ini sering disebut red, green, refactor:
- Red: tulis test kecil untuk sesuatu yang belum bisa dilakukan kode. Jalankan dan lihat test itu gagal.
- Green: tulis kode paling sederhana yang membuat test lulus.
- Refactor: rapikan kode, sementara test menjaga agar tidak ada yang rusak.
Lalu ulangi siklus itu untuk bagian kecil berikutnya.
Melihat test gagal lebih dulu itu penting. Itu membuktikan test tersebut memang bisa menangkap masalah. Test yang belum pernah gagal mungkin tidak menguji apa pun.
Kenapa memakai TDD untuk situs kecil?
Rasanya wajar melewatkan test untuk situs pribadi. Ukurannya kecil, dan tidak ada yang dibangunkan tengah malam kalau situsnya rusak.
Tapi situs kecil tetap bisa rusak dengan cara yang tidak terlihat di browser. Banyak bug di bawah ini hanya muncul di HTML yang dibaca mesin pencari. Test bisa menemukan bug seperti itu dalam hitungan detik.
Cara saya menyiapkan test untuk situs Astro
Saya memakai tiga jenis test, dari yang kecil sampai yang besar.
1. Unit test untuk fungsi kecil
Semua logika ada di fungsi TypeScript biasa, misalnya mengubah nama teknologi menjadi URL. Vitest menjalankan test ini dalam waktu kurang dari satu detik.
Menulis test lebih dulu membuat saya menentukan hasil yang diinginkan sebelum menulis kode. Misalnya, URL apa yang cocok untuk C#?
test('keeps meaning for symbol-heavy tech names', () => {
expect(slugify('C#')).toBe('csharp');
expect(slugify('C++')).toBe('cpp');
});
Versi sederhana dari fungsi ini akan memberi C, C#, dan C++ URL yang sama. Karena harus menulis hasil yang diharapkan, saya menyadarinya sejak awal.
2. Test komponen
Container API milik Astro bisa mengubah komponen menjadi HTML di dalam test. Saya memakainya untuk memeriksa bagian yang dipakai semua halaman, seperti header dan tag SEO.
3. Test pada situs yang sudah di-build
Lapisan inilah yang paling berharga. Script test membangun seluruh situs, lalu membuka setiap halaman HTML dan memeriksa hal yang penting bagi mesin pencari, misalnya:
test('has a canonical URL pointing to itself', () => {
expect(attr(html, /<link rel="canonical" href="([^"]+)"/)).toBe(expectedUrl);
});
Satu test seperti ini berjalan di setiap halaman dalam dua bahasa. Totalnya beberapa ratus pengecekan, dan semuanya selesai dalam hitungan detik.
4 bug nyata yang tertangkap TDD
1. Setiap halaman dialihkan ke alamat lain
Masalah: hosting saya (Cloudflare) menyajikan setiap halaman di alamat yang berakhiran garis miring, seperti /blog/my-post/, dan mengalihkan pengunjung yang membuka /blog/my-post ke sana.
Kenapa penting: setiap halaman memberi tahu mesin pencari alamat resminya, yang disebut canonical URL. Alamat resmi saya tidak berakhiran garis miring, jadi setiap alamat resmi mengarah ke pengalihan. Mesin pencari tidak menyukai itu.
Perbaikan: saya menulis test yang gagal untuk masalah ini lebih dulu. Lalu saya mengubah cara Astro menyimpan halaman, dari my-post/index.html menjadi my-post.html, sehingga tidak perlu pengalihan.
2. Perbaikan bug 1 menambahkan ".html" ke setiap alamat
Masalah: setelah perubahan itu, halaman melihat alamatnya sendiri sebagai /blog/my-post.html, dan akhiran itu ikut masuk ke alamat resmi.
Perbaikan: test pada situs yang sudah di-build gagal di setiap halaman, jadi saya langsung tahu. Saya menambahkan unit test untuk fungsi pembuat alamat, lalu memperbaikinya. Test yang sama juga menunjukkan bahwa menu berhenti menandai halaman yang sedang dibuka, karena alasan yang sama.
3. Feed RSS berisi link yang salah, tapi test tetap lulus
Masalah: test RSS pertama saya hanya memeriksa bahwa feed berisi alamat tulisan. Feed sebenarnya berisi alamat dengan garis miring tambahan, dan test tetap lulus, karena alamat yang benar adalah bagian dari alamat yang salah.
Perbaikan: saya membuat test lebih ketat, sehingga memeriksa link secara utuh. Test itu langsung gagal, dan perbaikannya cukup satu pengaturan di library RSS. Inilah alasan kenapa melihat test gagal itu penting.
4. Judul tulisan bisa merusak halaman
Masalah: setiap tulisan menyertakan data tersembunyi untuk mesin pencari di dalam tag <script>. Kalau judul tulisan berisi teks </script>, tag itu akan tertutup lebih awal dan merusak halaman.
Perbaikan: test komponen yang memakai teks persis seperti itu, lalu meng-escape karakter <.
Tips kalau Anda ingin mencoba TDD
- Mulai dari yang kecil. Pilih satu fungsi dengan input dan output yang jelas, lalu tulis test-nya lebih dulu.
- Uji apa yang diterima pengguna dan mesin pencari, bukan hanya fungsi Anda.
- Tulis test yang ketat. Pengecekan yang longgar bisa lulus meskipun hasilnya salah.
- Pisahkan data test dari konten asli. Beberapa test awal saya bergantung pada tulisan demo. Saat demo itu saya hapus, test tersebut tidak punya apa-apa lagi untuk diperiksa.
Kesimpulan
TDD tidak membuat proyek ini lebih lambat. Semua bug di atas tertangkap di laptop saya, dengan test gagal yang menjelaskan persis apa yang salah, bukan berminggu-minggu kemudian di laporan mesin pencari.
Baca tulisan lain tentang TDD, atau lihat pengalaman saya dengan Vitest.