Apa yang dipahami di bawah "unit" dalam pengujian unit

9

Seperti yang saya mengerti dalam teori di bawah "unit" berarti orang metode (dalam OOP). Tetapi dalam tes praktek yang memverifikasi beberapa metode dalam isolasi adalah tes perilaku yang sangat rapuh (memverifikasi bukan hasilnya tetapi fakta bahwa beberapa metode ketergantungan dipanggil). Jadi saya melihat banyak orang yang menurut unit memahami sekumpulan kecil kelas yang terkait erat. Dalam hal ini hanya dependensi luar yang diejek / di-stub dan untuk dependensi yang berada di dalam implementasi nyata unit digunakan. Dalam hal ini ada lebih banyak negara, bermakna (sesuai spesifikasi) dan tes tidak begitu rapuh. Jadi pertanyaannya adalah bagaimana perasaan Anda tentang pendekatan ini dan apakah valid untuk memanggil pengujian unit pendekatan kedua atau mungkin itu semacam pengujian integrasi tingkat rendah?

Jika Anda melihat beberapa pertimbangan khusus tentang penerapan TDD dengan salah satu cara pengujian ini, saya akan berterima kasih atas pemikiran Anda.

SiberianGuy
sumber

Jawaban:

11

Awalnya TDD berasal dari gerakan lincah, di mana pengujian ditulis di muka sebagai cara untuk memastikan apa yang Anda kodekan tetap benar mengingat spesifikasi yang sekarang didefinisikan dengan baik dalam kode pengujian. Itu juga muncul sebagai aspek yang sangat penting dari refactoring, ketika Anda memodifikasi kode Anda, Anda bisa mengandalkan tes untuk membuktikan bahwa Anda tidak mengubah perilaku kode.

Kemudian alat orang datang dan berpikir mereka tahu informasi tentang kode Anda dan kemudian dapat menghasilkan potongan uji untuk membantu Anda dalam menulis tes unit Anda, dan saya pikir ini adalah di mana semuanya salah.

Rintisan pengujian dihasilkan oleh komputer yang tidak memiliki petunjuk apa yang Anda lakukan, hanya menghasilkan sebuah rintisan tanpa berpikir untuk setiap metode karena itulah yang diperintahkan untuk dilakukan. Ini berarti Anda memiliki test case untuk setiap metode terlepas dari kompleksitas metode itu atau apakah cocok untuk pengujian secara terpisah.

Ini datang pada pengujian dari ujung metodologi TDD yang salah. Di TDD Anda harus mencari tahu apa kode yang harus dilakukan, dan kemudian menghasilkan kode yang mencapai ini. Ini memuaskan karena Anda akhirnya menulis tes yang membuktikan bahwa kode melakukan apa yang dilakukan kode, bukan apa yang seharusnya dilakukan. Dikombinasikan dengan penghentian bertopik pengujian berbasis metode secara otomatis, Anda membuang banyak waktu untuk membuktikan setiap aspek kecil dari kode Anda yang dengan mudah dapat terbukti salah ketika semua bagian kecil disatukan.

Ketika Fowler menggambarkan pengujian dalam bukunya, ia menyebut pengujian setiap kelas dengan metode utamanya sendiri. Dia meningkatkan ini, tetapi konsepnya masih sama - Anda menguji seluruh kelas sehingga bekerja secara keseluruhan, semua tes Anda digabungkan untuk membuktikan interaksi semua metode tersebut sehingga kelas dapat digunakan kembali dengan harapan yang ditentukan.

Saya pikir toolkit uji telah membuat kita merugikan, membawa kita ke jalan berpikir bahwa toolkit adalah satu-satunya cara untuk melakukan hal-hal ketika benar-benar, Anda perlu berpikir lebih banyak untuk diri sendiri untuk mendapatkan hasil terbaik dari kode Anda. Menempatkan kode tes dalam potongan tes kecil untuk potongan kecil hanya berarti Anda harus mengulangi pekerjaan Anda dalam tes integrasi (dan jika Anda akan melakukannya, mengapa tidak melewati tahap uji unit yang sekarang berlebihan sepenuhnya). Ini juga berarti orang membuang banyak waktu untuk mencoba mendapatkan cakupan tes 100%, dan banyak waktu membuat sejumlah besar kode ejekan dan data yang lebih baik dihabiskan untuk membuat kode lebih mudah untuk tes integrasi (yaitu jika Anda memiliki banyak dependensi data, unit test mungkin bukan pilihan terbaik)

Terakhir, kerapuhan unit test berbasis metode hanya menunjukkan masalahnya. Refactoring dirancang untuk digunakan dengan unit test, jika tes Anda rusak sepanjang waktu karena Anda refactoring maka ada yang tidak beres dengan seluruh pendekatan. Refactoring suka membuat dan menghapus metode, jadi jelas pendekatan tes buta per-metode bukanlah yang semula dimaksudkan.

Saya tidak ragu bahwa banyak metode akan mendapatkan tes tertulis untuk mereka, semua metode publik kelas harus diuji, tetapi Anda tidak dapat melepaskan diri dari konsep pengujian bersama sebagai bagian dari satu test case. Sebagai contoh, jika saya memiliki satu set dan metode get, saya dapat menulis tes yang memasukkan data dan memeriksa anggota internal diatur ok, atau saya dapat menggunakan masing-masing untuk memasukkan beberapa data dan kemudian mengeluarkannya lagi untuk melihat apakah itu masih sama dan tidak kacau. Ini menguji kelas, bukan masing-masing metode secara terpisah. Jika setter bergantung pada metode privat pembantu, maka itu tidak masalah - Anda tidak perlu mengejek metode pribadi untuk memastikan setter bekerja, tidak jika Anda menguji seluruh kelas.

Saya pikir agama masuk ke topik ini, maka Anda melihat perpecahan dalam apa yang sekarang dikenal sebagai pengembangan 'didorong oleh perilaku' dan 'didorong oleh ujian' - konsep asli pengujian unit adalah untuk pengembangan yang didorong oleh perilaku.

gbjbaanb
sumber
10

Suatu unit paling sering didefinisikan sebagai " bagian terkecil yang dapat diuji dari suatu aplikasi ". Lebih sering daripada tidak, ya, ini berarti suatu metode. Dan ya, ini berarti bahwa Anda tidak boleh menguji hasil dari metode dependen, tetapi metode itu dipanggil (dan hanya sekali, jika mungkin, tidak dalam setiap tes untuk metode itu).

Anda menyebut ini rapuh. Saya pikir itu tidak benar. Tes rapuh adalah tes yang menembus sedikit perubahan ke kode yang tidak terkait. Yaitu, mereka yang mengandalkan kode yang tidak relevan dengan fungsi yang diuji.

Namun, apa yang saya pikir Anda benar-benar ingin katakan adalah bahwa menguji suatu metode dengan tidak ada ketergantungan tidak menyeluruh. Pada titik itu saya setuju. Anda juga memerlukan tes integrasi untuk memastikan bahwa unit kode dihubungkan dengan benar untuk membuat aplikasi.

Ini adalah masalah yang harus dipecahkan oleh pengembangan yang digerakkan oleh perilaku , dan khususnya pengembangan yang digerakkan oleh tes penerimaan . Tetapi itu tidak menghilangkan kebutuhan untuk unit test / pengembangan berbasis tes; itu hanya melengkapi saja.

pdr
sumber
Saya benar-benar ingin mengatakan tes perilaku rapuh. Mereka sering menjadi negatif palsu selama perubahan basis kode. Itu kurang terjadi dengan tes negara (tetapi tes negara sangat jarang untuk pengujian unit)
SiberianGuy
@Idsa: Saya agak bingung dengan definisi Anda. Tes perilaku adalah tes integrasi, menguji sepotong perilaku seperti yang ditentukan. Membaca pertanyaan awal Anda, tampaknya ketika Anda mengatakan tes negara, Anda berarti hal yang sama.
pdr
maksud saya tes yang memverifikasi keadaan, hasil dari beberapa fungsi; maksud saya tes yang memverifikasi bukan hasil, tetapi fakta bahwa beberapa fungsi dipanggil
SiberianGuy
@Idsa: Dalam hal ini, saya benar-benar tidak setuju. Apa yang Anda sebut tes negara, saya sebut integrasi. Apa yang Anda panggil perilaku, saya sebut unit. Tes integrasi menurut definisi mereka lebih rapuh. Google "unit uji integrasi rapuh" dan Anda akan melihat bahwa saya tidak sendirian.
pdr
ada log artikel tentang pengujian tetapi mana dari mereka yang membagikan pendapat Anda?
SiberianGuy
2

Seperti namanya Anda menguji subjek atom dalam setiap tes. Subjek seperti itu biasanya merupakan metode tunggal. Beberapa pengujian dapat menguji metode yang sama, untuk menutupi jalan bahagia, kemungkinan kesalahan, dll. Anda menguji perilaku, bukan mekanisme internal. Jadi pengujian unit benar-benar tentang pengujian antarmuka publik kelas, yaitu metode tertentu.

Dalam pengujian unit, suatu metode perlu diuji secara terpisah, yaitu dengan mematikan / mengejek / memalsukan setiap dependensi. Kalau tidak, pengujian unit dengan dependensi 'nyata' menjadikannya sebagai tes integrasi. Ada waktu dan tempat untuk kedua jenis tes. Tes unit memastikan subjek tunggal berfungsi seperti yang diharapkan, mandiri. Tes integrasi memastikan bahwa subjek 'nyata' bekerja bersama dengan benar.

Grant Palin
sumber
1
tidak cukup, unit adalah subjek yang terisolasi, hanya karena perkakas otomatis lebih memilih untuk memperlakukan metode karena ini tidak membuatnya begitu, juga tidak menjadikannya yang terbaik. 'Terpencil' adalah kuncinya di sini. Bahkan jika Anda menguji metode, Anda juga harus menguji yang pribadi juga.
gbjbaanb
1

Aturan praktis saya: Unit terkecil dari kode yang masih cukup kompleks untuk mengandung bug.

Apakah ini metode atau kelas atau subsistem tergantung pada kode tertentu, tidak ada aturan umum yang dapat diberikan.

Misalnya, tidak memberikan nilai apa pun untuk menguji metode pengambil / penyetel sederhana secara terpisah, atau metode pembungkus yang hanya memanggil metode lain. Bahkan seluruh kelas mungkin terlalu sederhana untuk diuji, jika kelas tersebut hanya bungkus tipis atau adaptor. Jika satu-satunya hal yang diuji adalah jika metode pada mock dipanggil, maka kode yang diuji adalah thin.

Dalam kasus lain metode tunggal mungkin melakukan beberapa perhitungan kompleks yang berharga untuk diuji secara terpisah.

Dalam banyak kasus, bagian-bagian kompleks bukanlah kelas individu melainkan integrasi antar kelas. Jadi, Anda menguji dua atau lebih kelas sekaligus. Beberapa orang akan mengatakan bahwa ini bukan tes unit tetapi tes integrasi, tetapi tidak peduli terminologinya: Anda harus menguji di mana kompleksitasnya, dan tes ini harus menjadi bagian dari rangkaian uji.

JacquesB
sumber