Perspektif teknis, baik menguji maupun tidak

Tentukan hal yang perlu diuji dan hal yang dapat dikesampingkan.

Artikel sebelumnya membahas dasar-dasar kasus pengujian dan apa yang harus dimuat. Artikel ini menggali lebih dalam tentang pembuatan kasus pengujian dari perspektif teknis, dengan memerinci apa saja yang harus disertakan dalam setiap pengujian dan hal yang harus dihindari. Pada dasarnya, Anda akan mempelajari jawaban atas pertanyaan umum seperti "Apa yang harus diuji" atau "Apa yang tidak perlu diuji".

Yang perlu diuji atau tidak.

Pedoman dan pola umum

Perlu diperhatikan bahwa pola dan poin tertentu sangatlah penting, terlepas dari apakah Anda melakukan pengujian unit, integrasi, atau menyeluruh. Prinsip-prinsip ini dapat dan sebaiknya diterapkan pada kedua jenis pengujian, jadi ini adalah awal yang baik.

Jaga agar tetap simpel

Saat akan menulis pengujian, salah satu hal terpenting untuk diingat adalah membuatnya tetap sederhana. Penting untuk mempertimbangkan kapasitas otak. Kode produksi utama memakan banyak ruang yang signifikan, sehingga hanya menyisakan sedikit ruang untuk kompleksitas tambahan. Hal ini terutama berlaku untuk pengujian.

Jika headspace yang tersedia lebih sedikit, Anda dapat menjadi lebih santai dalam upaya pengujian. Itulah mengapa sangat penting untuk memprioritaskan kemudahan dalam pengujian. Bahkan, praktik terbaik pengujian JavaScript Yoni Goldberg menekankan pentingnya Aturan Utama—pengujian Anda harus terasa seperti asisten dan bukan seperti formula matematika yang kompleks. Dengan kata lain, Anda seharusnya dapat memahami maksud pengujian secara sekilas.

Jangan membuat pengujian menjadi rumit, mereka seharusnya tidak merasa seperti itu.

Anda harus mengincar kesederhanaan di semua jenis pengujian, terlepas dari kompleksitasnya. Bahkan, semakin kompleks pengujian, semakin penting untuk menyederhanakannya. Salah satu cara untuk mencapai hal ini adalah melalui desain pengujian datar, dengan pengujian yang dilakukan sesederhana mungkin, dan hanya menguji apa yang diperlukan. Artinya, setiap pengujian hanya boleh berisi satu kasus pengujian, dan kasus pengujian harus difokuskan pada pengujian satu fungsi atau fitur tertentu.

Pikirkan dari perspektif ini: seharusnya mudah untuk mengidentifikasi kesalahan saat membaca pengujian yang gagal. Inilah alasan pentingnya membuat pengujian tetap sederhana dan mudah dipahami. Tindakan ini memungkinkan Anda mengidentifikasi dan memperbaiki masalah yang muncul dengan cepat.

Uji kemampuan Anda

Desain tes datar juga mendorong fokus dan membantu memastikan pengujian Anda bermakna. Ingat, Anda tidak ingin membuat pengujian hanya untuk cakupan—pengujian harus selalu memiliki tujuan.

Jangan menguji semua hal.

Jangan menguji detail penerapan

Satu masalah umum dalam pengujian adalah pengujian sering kali didesain untuk menguji detail implementasi, seperti menggunakan pemilih dalam komponen atau pengujian end-to-end. Detail penerapan mengacu pada hal-hal yang biasanya tidak akan digunakan, dilihat, atau diketahui oleh pengguna kode Anda. Hal ini dapat menyebabkan dua masalah utama dalam pengujian: negatif palsu dan positif palsu.

Negatif palsu terjadi saat pengujian gagal, meskipun kode yang diuji sudah benar. Hal ini dapat terjadi saat detail implementasi berubah karena pemfaktoran ulang kode aplikasi. Di sisi lain, positif palsu terjadi ketika pengujian lulus, meskipun kode yang diuji salah.

Salah satu solusi untuk masalah ini adalah dengan mempertimbangkan berbagai jenis pengguna yang Anda miliki. Pengguna akhir dan developer dapat berbeda dalam pendekatan mereka, dan mereka dapat berinteraksi dengan kode secara berbeda. Saat merencanakan pengujian, penting untuk mempertimbangkan apa yang akan dilihat atau berinteraksi dengan pengguna, dan membuat pengujian bergantung pada hal-hal tersebut, bukan detail implementasi.

Misalnya, memilih pemilih yang tidak terlalu rentan terhadap perubahan dapat membuat pengujian lebih andal, yaitu atribut data, bukan pemilih CSS. Untuk mengetahui detail selengkapnya, lihat Kent C. Artikel Dodds tentang topik ini akan segera tersedia, atau nantikan—artikel tentang topik ini akan tersedia nanti.

Tiruan: Jangan sampai kehilangan kendali

Tiruan adalah konsep luas yang digunakan dalam pengujian unit dan terkadang dalam pengujian integrasi. Ini melibatkan pembuatan data atau komponen palsu untuk menyimulasikan dependensi yang memiliki kontrol penuh atas aplikasi. Hal ini memungkinkan pengujian terpisah.

Menggunakan tiruan dalam pengujian dapat meningkatkan prediktabilitas, pemisahan fokus, dan performa. Selain itu, jika Anda perlu melakukan tes yang memerlukan keterlibatan manusia (seperti verifikasi paspor), Anda harus menyembunyikannya menggunakan tiruan. Untuk semua alasan ini, {i>mockup<i} adalah alat yang berharga untuk dipertimbangkan.

Pada saat yang sama, tiruan dapat memengaruhi akurasi pengujian karena itu adalah tiruan, bukan pengalaman pengguna yang sebenarnya. Jadi, Anda harus berhati-hati saat menggunakan {i>mockup <i}dan stub.

Haruskah Anda membuat tiruan dalam pengujian end-to-end?

Secara umum, tidak. Namun, mengejek kadang-kadang bisa menjadi penyelamat—jadi jangan mengesampingkan hal ini sepenuhnya.

Bayangkan skenario ini: Anda sedang menulis pengujian untuk fitur yang melibatkan layanan penyedia pembayaran pihak ketiga. Anda berada di lingkungan {i>sandbox<i} yang mereka sediakan, yang berarti tidak ada transaksi nyata yang terjadi. Sayangnya, {i>sandbox <i}tidak berfungsi, sehingga menyebabkan pengujian Anda gagal. Perbaikan harus dilakukan oleh penyedia jasa pembayaran. Yang dapat Anda lakukan hanyalah menunggu hingga masalah ini diselesaikan oleh penyedia.

Dalam hal ini, akan lebih baik jika Anda mengurangi ketergantungan pada layanan yang tidak dapat Anda kontrol. Sebaiknya tetap gunakan tiruan dengan hati-hati dalam integrasi atau pengujian menyeluruh karena dapat menurunkan tingkat kepercayaan pengujian Anda.

Detail pengujian: Anjuran dan larangan

Jadi, secara keseluruhan, apa saja yang tercakup dalam pengujian? Dan apakah ada perbedaan di antara jenis-jenis pengujian? Mari kita pelajari lebih lanjut beberapa aspek spesifik yang disesuaikan dengan jenis pengujian utama.

Apa yang termasuk dalam pengujian unit yang baik?

Pengujian unit yang ideal dan efektif harus:

  • Berkonsentrasi pada aspek tertentu.
  • Beroperasi secara independen.
  • Mencakup skenario skala kecil.
  • Gunakan nama deskriptif.
  • Ikuti pola AAA jika berlaku.
  • Menjamin cakupan pengujian yang komprehensif.
Lakukan ✅ Jangan ❌
Pastikan pengujian sekecil mungkin. Uji satu hal per kasus pengujian. Menulis pengujian di unit besar.
Selalu pisahkan pengujian dan tiruan hal-hal yang Anda perlukan yang berada di luar unit. Sertakan komponen atau layanan lainnya.
Jaga agar pengujian tetap independen. Andalkan pengujian sebelumnya atau bagikan data pengujian.
Mempelajari berbagai skenario dan jalur. Batasi diri Anda pada {i>happy path<i} atau pengujian negatif secara maksimal.
Gunakan judul pengujian deskriptif, sehingga Anda dapat langsung melihat isi pengujian. Uji berdasarkan nama fungsi saja, hasilnya tidak cukup deskriptif: testBuildFoo() atau testGetId().
Targetkan cakupan kode yang baik atau kasus pengujian yang lebih luas, terutama pada tahap ini. Uji dari setiap class hingga tingkat database (I/O).

Apa saja yang termasuk dalam pengujian integrasi yang baik?

Pengujian integrasi ideal juga memiliki beberapa kriteria yang sama dengan pengujian unit. Namun, ada beberapa poin tambahan yang perlu Anda pertimbangkan. Pengujian integrasi yang baik harus:

  • Menyimulasikan interaksi antar komponen.
  • Pelajari skenario dunia nyata dan gunakan tiruan atau stub.
  • Mempertimbangkan performa.
Lakukan ✅ Jangan ❌
Uji titik integrasi: pastikan setiap unit berfungsi dengan baik jika saling terintegrasi. Uji setiap unit secara terpisah—untuk itulah pengujian unit.
Uji skenario dunia nyata: gunakan data uji coba yang berasal dari data dunia nyata. Gunakan data pengujian berulang yang dibuat secara otomatis atau data lain yang tidak mencerminkan kasus penggunaan dunia nyata.
Gunakan tiruan dan stub untuk dependensi eksternal guna mempertahankan kontrol atas pengujian Anda secara menyeluruh. Membuat dependensi pada layanan pihak ketiga, misalnya, permintaan jaringan ke layanan luar.
Gunakan rutinitas pembersihan sebelum dan setelah setiap pengujian. Lupakan untuk menggunakan langkah-langkah pembersihan dalam pengujian Anda. Jika tidak, hal ini dapat menyebabkan kegagalan uji atau positif palsu, karena kurangnya isolasi pengujian yang tepat.

Apa saja yang termasuk pengujian menyeluruh yang baik?

Pengujian menyeluruh yang komprehensif harus:

  • Replikasikan interaksi pengguna.
  • Mencakup skenario penting.
  • Mencakup beberapa lapisan.
  • Mengelola operasi asinkron.
  • Verifikasi hasil.
  • Memperhitungkan performa.
Lakukan ✅ Jangan ❌
Gunakan pintasan berbasis API. Pelajari lebih lanjut. Gunakan interaksi UI untuk setiap langkah, termasuk hook beforeEach.
Gunakan rutinitas pembersihan sebelum setiap pengujian. Usahakan isolasi pengujian lebih ketat daripada yang Anda lakukan di pengujian unit dan integrasi karena risiko efek samping lebih tinggi di sini. Lupa melakukan pembersihan setelah setiap pengujian. Jika Anda tidak membersihkan status, data, atau efek samping yang tersisa, keduanya akan memengaruhi pengujian lain yang dijalankan nanti.
Menganggap pengujian menyeluruh sebagai pengujian sistem. Artinya, Anda perlu menguji seluruh stack aplikasi. Uji setiap unit secara terpisah—untuk itulah pengujian unit.
Gunakan sedikit atau tanpa tiruan di dalam pengujian. Pertimbangkan dengan cermat jika Anda ingin meniru dependensi eksternal. Sangat mengandalkan tiruan.
Pertimbangkan performa dan beban kerja dengan, misalnya, tidak menguji skenario besar secara berlebihan dalam pengujian yang sama. Terapkan alur kerja yang luas tanpa menggunakan pintasan.