Apakah masuk akal untuk tidak menulis tes unit karena cenderung dikomentari nanti atau karena tes integrasi lebih berharga?

35

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.

Jeff Levine
sumber
9
Anda sendiri yang mengatakan: menulis unit test menghasilkan kode yang lebih baik, karena memaksa Anda untuk menulis kode yang dapat diuji. Kode unit-testable memiliki banyak properti yang sangat penting yang meningkatkan kualitas keseluruhannya.
Robert Harvey
1
@Robert Harvey - Setuju - Saya tertarik untuk melihat daftar properti ini.
Jeff Levine
18
Adapun poin pertama - Anda pada dasarnya mengatakan kelemahan dari tes unit adalah bahwa mereka tidak berfungsi ketika Anda tidak menggunakannya. Anda dapat mengatakan hal yang sama tentang latihan lainnya. Selain itu, penggunaan suara pasif Anda mengabaikan fakta bahwa seseorang secara aktif mengomentari tes unit. Jadi sepertinya Anda tidak menerima dari pengembang di tim, yang merupakan masalah berbeda.
JacquesB

Jawaban:

62

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.

Denis de Bernardy
sumber
13
Ini, ini, seratus kali ini. Ini adalah hal yang hebat tentang pengembangan yang digerakkan oleh tes. Menulis tes terlebih dahulu akan membantu Anda menulis tes yang tidak menguji rincian implementasi Anda tetapi perilaku yang dimaksud yang Anda coba terapkan.
wirrbel
9
Saya pikir tes unit rapuh bukan sifat yang melekat pada pengujian unit, tetapi bukannya kesalahpahaman untuk apa pengujian unit ada. Yang kita butuhkan di sini adalah pendidikan yang lebih baik bagi para pengembang. Jika Anda unit detail implementasi tes, Anda melakukannya salah . Jika Anda membuat metode pribadi publik "untuk menguji mereka", Anda salah melakukannya . Selalu uji antarmuka publik & perilaku, yang seharusnya lebih jarang berubah daripada detail implementasi!
Andres F.
2
@DocBrown: Memang tidak. Yang saya maksudkan adalah, sering kali melakukan kesalahan sehingga kolega OP benar dalam sebagian besar kasus - atau setidaknya dalam semua kasus yang pernah saya alami di perusahaan-perusahaan yang terobsesi dengan pengujian unit.
Denis de Bernardy
3
@DenisdeBernardy: maksud saya adalah: semua yang Anda tulis pasti benar dengan banyak kebijaksanaan dari praktik, tetapi saya kehilangan kesimpulan apa artinya bagi kasus OP dengan rekannya, dalam konteks saran "tes integrasi sebagai alternatif yang lebih baik ".
Doc Brown
5
Saya sangat setuju dengan Doc Brown. Pada dasarnya, posisi Anda tampaknya adalah bahwa unit test baik, tetapi ketika mereka ditulis dengan buruk, mereka menjadi merepotkan. Jadi, Anda tidak setuju dengan kolega OP sama sekali, hanya bahwa Anda harus memastikan bahwa Anda benar-benar menulis unit test sebelum menegaskan kegunaannya. Saya pikir jawaban Anda sangat membingungkan karena kalimat pertama menyatakan Anda setuju dengan kolega OP ketika tampaknya tidak demikian. Itu lebih seperti kata-kata kasar tentang unit test yang ditulis dengan buruk (yang merupakan masalah dalam praktiknya, saya akui), bukan kasus terhadap unit test pada umumnya.
Vincent Savard
38

Ketika perubahan kode besar terjadi, unit test cenderung dikomentari alih-alih dikerjakan ulang.

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.

Waktu lebih baik dihabiskan untuk tes integrasi yang mencakup kasus penggunaan yang membuat tes dengan cakupan yang lebih kecil kurang / tidak sama sekali penting.

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.

Doc Brown
sumber
Ini sangat saya rasakan ketika kami mendiskusikannya. Dengan asumsi tes integrasi penuh dan relevan dapat ditulis untuk kasus penggunaan, sepertinya tes unit akan menjadi titik diperdebatkan. (Walaupun sekarang saya menulis ini, saya memikirkan kasus-kasus yang tidak terduga di masa depan - seperti backend kami yang diubah menjadi layanan web untuk aplikasi lain).
Jeff Levine
+1 Untuk "Anda harus bekerja pada definisi selesai". Dikatakan dengan baik!
Andres F.
14

Saya tidak tahu bahwa saya menerima argumen rekan Anda.

  1. Jika tes unit dikomentari, itu karena seseorang malas. Itu bukan kesalahan unit test. Dan jika Anda mulai menggunakan malas sebagai alasan, Anda bisa membantah hampir semua praktik yang membutuhkan sedikit usaha.
  2. Jika Anda melakukannya dengan benar, unit test tidak perlu waktu lama. Mereka tidak menghentikan Anda dari melakukan pekerjaan yang lebih penting. Jika kita semua sepakat bahwa memperbaiki kode yang rusak lebih penting daripada yang lain, sebuah unit test sangat penting. Ini cara mudah untuk menguji kondisi pos. Tanpa itu, bagaimana Anda tahu Anda telah memenuhi jaminan kondisi pos? Dan jika Anda belum melakukannya, kode Anda rusak.

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:

Hanya sedikit Roger
sumber
+1 untuk artikel itu, mungkin jawaban yang lebih baik untuk kasus OP daripada semua yang dapat kita tulis di sini
Doc Brown
+1 untuk poin nomor 1 tentang kemalasan menjadi alasan. Saya tidak bisa cukup menekankan betapa frustrasinya hal itu. Aku pernah disana. Baru-baru ini, sebenarnya.
Greg Burghardt
3
Alasan 1 bukanlah kesalahan unit test, tapi itu masih menjadi alasan terhadap unit test.
user253751
Setelah membaca artikel DHH, pastikan Anda melihat video di mana ia mendiskusikan topik tersebut dengan Kent Beck dan Martin Fowler (mereka ada di youtube) - banyak orang tampaknya mendapatkan versi yang lebih ekstrim dari maksudnya daripada yang ia maksudkan, dan dia sedikit memperhalusnya dalam diskusi ini.
Jules
6

Ketika perubahan kode besar terjadi (set POJO baru, refactoring aplikasi utama, dll.), Tes unit cenderung dikomentari alih-alih dikerjakan ulang.

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
4

unit test cenderung dikomentari daripada dikerjakan ulang.

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.

Philip Kendall
sumber
3

Ketika perubahan kode besar terjadi (set POJO baru, refactoring aplikasi utama, dll.), Tes unit cenderung dikomentari alih-alih dikerjakan ulang.

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.

Waktu lebih baik dihabiskan untuk tes integrasi yang mencakup kasus penggunaan, yang membuat tes dengan cakupan yang lebih kecil kurang / tidak sama sekali penting.

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.

kasperd
sumber
3

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.

Michael Shaw
sumber
3

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:

  1. 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 ...

  2. 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 ...

  3. 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.

AK_
sumber
2

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.

Ewan
sumber
+1 karena berusaha menjawab pertanyaan yang diajukan dengan sungguh-sungguh.
RubberDuck
2
Biaya unit test pasti tidak kecil. Tes unit yang baik biasanya membutuhkan waktu lebih lama untuk menulis daripada apa yang mereka uji. Sebagian besar waktu manfaat melebihi biaya.
AK_
1
dalam teori saja - ketika Anda refactor, Anda berakhir dengan biaya besar memperbarui tes unit juga karena mereka hampir selalu terlalu terperinci. Jika Anda berbicara tentang memiliki test suite integrasi yang baik, maka Anda akan benar.
gbjbaanb
Jika sebuah proyek cukup singkat dan tidak memerlukan pemeliharaan / pembaruan yang berkelanjutan - sebagian besar sistem warisan telah dimulai sebagai proyek pendek tanpa tes - dan berakhir dengan mempekerjakan lebih banyak pengembang untuk mempertahankan sistem yang berkembang tanpa tes
Fabio