Saya sedang mendiskusikan pengujian unit / integrasi dengan seorang kolega, dan dia membuat kasus yang menarik terhadap penulisan tes unit. Saya pendukung unit test besar (terutama JUnit), tetapi saya tertarik mendengar pendapat orang lain, karena ia membuat beberapa poin menarik.
Untuk meringkas poinnya:
- Ketika perubahan kode besar terjadi (set POJO baru, refactoring aplikasi utama, dll.), Tes unit cenderung dikomentari alih-alih dikerjakan ulang.
- Waktu lebih baik dihabiskan untuk tes integrasi yang mencakup kasus penggunaan, yang membuat tes dengan cakupan yang lebih kecil kurang / tidak sama sekali penting.
Pikiran tentang ini? Saya masih pro-unit test (seperti yang saya lihat secara konsisten menghasilkan kode yang lebih baik), meskipun tes integrasi terdengar setidaknya sama berharganya.
unit-testing
integration-tests
Jeff Levine
sumber
sumber
Jawaban:
Saya cenderung memihak teman Anda karena terlalu sering, unit test menguji hal-hal yang salah .
Tes unit pada dasarnya tidak buruk. Tetapi mereka sering menguji rincian implementasi daripada aliran input / output. Anda berakhir dengan tes yang sama sekali tidak berguna saat ini terjadi. Aturan saya sendiri adalah bahwa unit test yang baik memberi tahu Anda bahwa Anda baru saja memecahkan sesuatu; tes unit yang buruk hanya memberi tahu Anda bahwa Anda baru saja mengubah sesuatu.
Contoh dari atas kepala saya adalah satu tes yang terselip di WordPress beberapa tahun yang lalu. Fungsionalitas yang diuji berkisar pada filter yang saling memanggil, dan tes memverifikasi bahwa panggilan balik kemudian akan dipanggil dalam urutan yang benar. Tetapi alih-alih (a) menjalankan rantai untuk memverifikasi bahwa panggilan balik dipanggil dalam urutan yang diharapkan, tes difokuskan pada (b) membaca beberapa keadaan internal yang mungkin seharusnya tidak terpapar sejak awal. Ubah internal dan (b) berubah merah; sedangkan (a) hanya berubah merah jika perubahan pada bagian dalam mematahkan hasil yang diharapkan saat melakukannya. (B) jelas tes yang tidak berguna menurut saya.
Jika Anda memiliki kelas yang memaparkan beberapa metode ke dunia luar, hal yang benar untuk diuji dalam pandangan saya adalah metode yang terakhir saja . Jika Anda menguji logika internal juga, Anda mungkin akhirnya mengekspos logika internal ke dunia luar, menggunakan metode pengujian yang berbelit-belit, atau dengan litani unit test yang selalu rusak setiap kali Anda ingin mengubah apa pun.
Dengan semua yang dikatakan, saya akan terkejut jika teman Anda sama kritisnya dengan unit test per se seperti yang Anda sarankan. Daripada aku kumpulkan dia pragmatis. Artinya, ia mengamati bahwa tes unit yang ditulis sebagian besar tidak ada gunanya dalam praktek. Mengutip: "unit test cenderung dikomentari daripada dikerjakan ulang". Bagi saya ada pesan implisit di sana - jika mereka cenderung perlu mengerjakan ulang itu karena mereka cenderung payah. Dengan asumsi demikian, proposisi kedua berikut: pengembang akan membuang lebih sedikit waktu menulis kode yang lebih sulit untuk mendapatkan kesalahan - yaitu tes integrasi.
Dengan demikian ini bukan tentang seseorang menjadi lebih baik atau lebih buruk. Hanya saja, jauh lebih mudah untuk salah, dan memang sangat sering salah dalam praktik.
sumber
Dengan sekelompok pembuat kode koboi yang tidak disiplin yang berpikir bahwa semua tes yang mendapatkan "hijau" terpenuhi ketika Anda mengomentari semua tes yang ada: tentu saja. Tes unit pengerjaan ulang membutuhkan jumlah disiplin yang sama dengan menuliskannya di tangan pertama, jadi apa yang harus Anda kerjakan di sini adalah "definisi selesai" tim Anda.
Itu tidak sepenuhnya salah atau sepenuhnya benar. Upaya untuk menulis tes integrasi yang bermanfaat sangat tergantung pada jenis perangkat lunak yang Anda tulis. Jika Anda memiliki perangkat lunak di mana tes integrasi dapat dengan mudah ditulis sebagai tes unit, tes tersebut berjalan dengan cepat dan memberi Anda cakupan kode yang baik, maka rekan Anda ada benarnya. Tetapi untuk banyak sistem saya telah melihat tiga poin ini tidak dapat dengan mudah dipenuhi oleh tes integrasi, itu sebabnya Anda harus berusaha keras untuk juga memiliki unit test.
sumber
Saya tidak tahu bahwa saya menerima argumen rekan Anda.
Ada argumen lain yang lebih meyakinkan tentang tes unit. Yah, tidak persis menentang mereka. Mulailah dengan kerusakan desain yang diinduksi oleh Uji DHH . Dia penulis yang menyenangkan, jadi bacalah. Apa yang saya ambil dari itu:
Jika Anda membuat perubahan desain besar untuk mengakomodasi pengujian unit Anda, mereka dapat menghambat tujuan lain dalam proyek Anda. Jika memungkinkan, tanyakan pada orang yang tidak memihak mana pendekatan yang lebih mudah diikuti. Jika kode Anda yang sangat dapat diuji sulit dipahami, Anda mungkin kehilangan semua manfaat yang Anda peroleh dari pengujian unit. Overhead kognitif dari terlalu banyak abstraksi memperlambat Anda dan membuat kesalahan bocor lebih mudah. Jangan diskon itu.
Jika Anda ingin bernuansa dan filosofis, ada banyak sumber daya hebat:
sumber
Jangan lakukan itu. Jika Anda menemukan seseorang yang melakukan itu, bunuh mereka dan pastikan mereka tidak bereproduksi, karena anak-anak mereka mungkin mewarisi gen yang rusak itu. Kuncinya seperti yang saya lihat dari menonton acara televisi CSI adalah menyebarkan banyak sampel DNA yang menyesatkan di mana-mana. Dengan cara ini Anda mengotori tempat kejadian dengan begitu banyak kebisingan sehingga, mengingat sifat pengujian DNA yang mahal dan memakan waktu, kemungkinan mereka akan menjelaskannya kepada Anda sangat rendah.
sumber
Pada titik mana proses peninjauan kode mengatakan "perbaiki unit test" dan ini bukan masalah lagi :-) Jika proses peninjauan kode Anda tidak menangkap cacat utama semacam ini dalam kode yang dikirimkan, maka itulah masalahnya.
sumber
Saya selalu berusaha untuk menjaga refactoring dan mengubah fungsi secara terpisah. Ketika saya perlu melakukan keduanya, saya biasanya melakukan refactoring terlebih dahulu.
Ketika kode refactoring tanpa mengubah fungsionalitas, unit test yang ada diharapkan untuk membantu memastikan bahwa refactoring tidak merusak fungsionalitas secara tidak sengaja. Jadi untuk komitmen semacam itu, saya akan mempertimbangkan menonaktifkan atau menghapus unit test sebagai tanda peringatan utama. Setiap pengembang yang melakukannya harus diberitahu untuk tidak melakukannya ketika kode sedang ditinjau.
Ada kemungkinan bahwa perubahan yang tidak mengubah fungsi masih menyebabkan tes unit gagal karena tes unit cacat. Jika Anda memahami kode yang Anda ubah maka penyebab kegagalan unit test tersebut biasanya langsung jelas dan mudah diperbaiki.
Sebagai contoh jika suatu fungsi mengambil tiga argumen, tes unit yang mencakup interaksi antara dua argumen pertama untuk fungsi tersebut mungkin tidak hati-hati untuk memberikan nilai yang valid untuk argumen ketiga. Kelemahan dalam pengujian unit ini dapat diekspos oleh refactoring dari kode yang diuji, tetapi mudah untuk diperbaiki jika Anda memahami apa yang seharusnya dilakukan oleh kode dan apa yang diuji oleh unit test.
Saat mengubah fungsionalitas yang ada, biasanya perlu juga mengubah beberapa tes unit. Dalam kasus ini, unit test membantu memastikan bahwa kode Anda mengubah fungsionalitas seperti yang dimaksudkan dan tidak memiliki efek samping yang tidak diinginkan.
Saat memperbaiki bug atau menambahkan fungsionalitas baru, seseorang biasanya perlu menambahkan lebih banyak tes unit. Bagi mereka itu dapat membantu untuk melakukan pengujian unit terlebih dahulu dan melakukan perbaikan bug atau fungsionalitas baru nanti. Itu membuatnya lebih mudah untuk memverifikasi bahwa tes unit baru tidak lulus dengan kode yang lebih lama tetapi lulus dengan kode yang lebih baru. Pendekatan ini tidak sepenuhnya tanpa kelemahan, jadi ada juga argumen yang mendukung melakukan pengujian unit baru dan pembaruan kode secara bersamaan.
Ada beberapa unsur kebenaran dalam hal ini. Jika Anda bisa mendapatkan cakupan lapisan bawah tumpukan perangkat lunak dengan tes yang menargetkan lapisan yang lebih tinggi dari tumpukan perangkat lunak, tes Anda mungkin lebih bermanfaat ketika melakukan refactoring kode.
Saya tidak berpikir Anda akan menemukan kesepakatan tentang perbedaan yang tepat antara tes unit dan tes integrasi. Dan saya tidak akan khawatir jika Anda memiliki test case yang satu pengembang memanggil unit test dan yang lainnya memanggil test integrasi, selama mereka dapat setuju bahwa itu adalah case test yang bermanfaat.
sumber
Tes integrasi dilakukan untuk memeriksa apakah sistem berperilaku sebagaimana mestinya, yang selalu memiliki nilai bisnis. Tes unit tidak selalu melakukan itu. Tes unit dapat menguji kode mati, misalnya.
Ada filosofi pengujian yang mengatakan bahwa setiap tes yang tidak memberi Anda informasi adalah sia-sia. Ketika sepotong kode tidak sedang dikerjakan, tes unitnya selalu (atau hampir selalu) akan berwarna hijau, memberi Anda sedikit atau tidak ada informasi.
Setiap metode pengujian tidak akan lengkap. Bahkan jika Anda mendapatkan cakupan 100% dengan beberapa metrik, Anda masih belum melalui hampir setiap set data input yang mungkin. Jadi, jangan berpikir unit test itu ajaib.
Saya sering melihat klaim bahwa memiliki unit test meningkatkan kode Anda. Menurut pendapat saya, perbaikan yang dilakukan oleh unit test pada kode memaksa orang yang tidak terbiasa memecah kode mereka menjadi bagian-bagian kecil yang diperhitungkan dengan baik. Jika Anda terbiasa mendesain kode Anda dalam ukuran kecil, dengan faktor yang baik, Anda mungkin menemukan bahwa Anda tidak perlu pengujian unit untuk memaksa Anda melakukannya lagi.
Tergantung pada seberapa besar Anda menguji unit dan seberapa besar program Anda, Anda mungkin berakhir dengan sejumlah besar tes unit. Jika demikian, perubahan besar menjadi lebih sulit. Jika perubahan besar menyebabkan banyak tes unit gagal, Anda dapat menolak untuk melakukan perubahan, melakukan banyak pekerjaan untuk memperbaiki banyak tes, atau membuang tes. Tidak ada pilihan yang ideal.
Tes unit adalah alat di dalam kotak alat. Mereka ada di sana untuk melayani Anda, bukan sebaliknya. Pastikan untuk keluar dari mereka setidaknya sebanyak yang Anda masukkan.
sumber
Unit test jelas bukan peluru perak yang diklaim oleh beberapa pendukungnya. Tetapi secara umum mereka memiliki rasio biaya / manfaat yang sangat positif. Mereka tidak akan membuat kode Anda "lebih baik", mungkin lebih modular. "lebih baik" memiliki lebih banyak faktor daripada apa yang disiratkan "diuji". Tetapi mereka akan memastikan itu berfungsi dalam semua kasus dan penggunaan yang Anda pikirkan, dan akan menghilangkan sebagian besar bug Anda (mungkin yang lebih sepele).
Namun, manfaat terbesar dari unit test adalah membuat kode Anda lebih fleksibel, dan tahan terhadap perubahan. Anda dapat memperbaiki atau menambahkan fitur, dan cukup yakin Anda tidak merusak apa pun. Ini saja membuat mereka berharga untuk sebagian besar proyek.
Mengacu pada poin yang dibuat oleh teman Anda:
Jika menambahkan POJO merusak pengujian unit Anda, maka itu mungkin ditulis dengan sangat buruk. POJO biasanya bahasa yang Anda gunakan untuk berbicara tentang domain Anda, dan masalah yang Anda selesaikan, mengubahnya jelas berarti seluruh logika bisnis Anda, dan mungkin kode presentasi harus diubah. Anda tidak dapat mengharapkan apa yang memastikan bagian-bagian dari program Anda berfungsi untuk tidak berubah ...
Mengeluh bahwa tes Unit buruk, karena orang-orang berkomentar, seperti mengeluh sabuk pengaman buruk karena orang tidak memakainya. Jika seseorang mengomentari kode pengujian dan merusak sesuatu, ia harus berakhir dalam percakapan yang sangat serius dan tidak menyenangkan dengan bosnya ...
Tes integrasi jauh lebih unggul daripada tes unit. tidak ada pertanyaan. terutama jika Anda menguji suatu produk. Tetapi menulis tes integrasi yang baik dan komprehensif, yang akan memberi Anda nilai, cakupan, dan jaminan kebenaran yang sama dengan yang diberikan unit test, sangat sulit.
sumber
Saya hanya bisa memikirkan satu argumen terhadap unit test, dan itu cukup lemah.
Tes unit menunjukkan sebagian besar nilainya ketika Anda refactor atau mengubah kode pada tahap selanjutnya. Anda melihat pengurangan besar dalam waktu yang diperlukan untuk menambahkan fitur dan memastikan Anda tidak merusak apa pun.
Namun: Ada biaya (kecil) pada saat tes menulis di tempat pertama sekalipun.
Oleh karena itu: Jika suatu proyek cukup singkat dan tidak memerlukan pemeliharaan / pembaruan yang berkelanjutan, ada kemungkinan bahwa biaya tes penulisan lebih besar daripada manfaatnya.
sumber