Saya menemukan tes jauh lebih sulit dan sulit untuk ditulis daripada kode aktual yang mereka uji. Ini tidak biasa bagi saya untuk menghabiskan lebih banyak waktu menulis tes daripada kode yang diuji.
Apakah itu normal atau saya melakukan sesuatu yang salah?
Pertanyaan “ Apakah pengujian unit atau pengembangan yang digerakkan oleh pengujian bermanfaat? ”,“ Kami menghabiskan lebih banyak waktu untuk mengimplementasikan tes fungsional daripada mengimplementasikan sistem itu sendiri, apakah ini normal? ”Dan jawaban mereka lebih lanjut tentang apakah pengujian itu layak (seperti dalam" haruskah kita melewatkan tes menulis sama sekali? "). Sementara saya yakin tes itu penting, saya bertanya-tanya apakah saya menghabiskan lebih banyak waktu untuk tes daripada kode yang sebenarnya adalah normal atau apakah hanya saya.
Menilai dari jumlah pandangan, jawaban, dan peningkatan pertanyaan saya yang diterima, saya hanya bisa menganggap itu masalah sah yang tidak dibahas dalam pertanyaan lain di situs web.
sumber
Jawaban:
Saya ingat dari kursus rekayasa perangkat lunak, yang dihabiskan ~ 10% dari waktu pengembangan untuk menulis kode baru, dan 90% lainnya adalah debugging, pengujian, dan dokumentasi.
Karena unit-test menangkap debugging, dan menguji upaya ke dalam kode (yang berpotensi dapat diotomatiskan), masuk akal bahwa lebih banyak upaya yang dilakukan ke dalamnya; waktu aktual yang diambil seharusnya tidak lebih dari debugging dan pengujian yang akan dilakukan tanpa menulis tes.
Akhirnya tes juga harus berfungsi ganda sebagai dokumentasi! Seseorang harus menulis unit-test dengan cara kode dimaksudkan untuk digunakan; yaitu tes (dan penggunaan) harus sederhana, letakkan hal-hal rumit dalam implementasi.
Jika tes Anda sulit untuk ditulis, kode yang mereka uji mungkin sulit digunakan!
sumber
Ini.
Bahkan jika Anda hanya melakukan pengujian unit, bukan tidak biasa memiliki lebih banyak kode dalam pengujian daripada kode yang sebenarnya diuji. Tidak ada yang salah dengan itu.
Pertimbangkan kode sederhana:
Apa yang akan menjadi tes? Setidaknya ada empat kasus sederhana untuk diuji di sini:
Nama orang itu
null
. Apakah pengecualian benar-benar dilemparkan? Itu setidaknya tiga baris kode tes untuk ditulis.Nama orang itu
"Jeff"
. Apakah kita mendapat"Hello, Jeff!"
tanggapan? Itu empat baris kode uji.Nama orang adalah string kosong. Output apa yang kita harapkan? Apa hasil aktualnya? Pertanyaan sampingan: apakah cocok dengan persyaratan fungsional? Itu berarti empat baris kode lain untuk unit test.
Nama orang cukup pendek untuk sebuah string, tetapi terlalu panjang untuk digabungkan dengan
"Hello, "
dan tanda seru. Apa yang terjadi? ¹Ini membutuhkan banyak kode pengujian. Selain itu, potongan kode yang paling dasar sering memerlukan kode pengaturan yang menginisialisasi objek yang diperlukan untuk kode yang diuji, yang juga sering menyebabkan tulisan bertopik dan mengolok-olok, dll.
Jika rasionya sangat besar, dalam hal ini Anda dapat memeriksa beberapa hal:
Apakah ada duplikasi kode di seluruh tes? Fakta bahwa itu kode uji tidak berarti bahwa kode tersebut harus digandakan (copy-paste) antara tes yang sama: duplikasi seperti itu akan membuat pemeliharaan tes tersebut sulit.
Apakah ada tes yang berlebihan? Sebagai aturan praktis, jika Anda menghapus unit test, jangkauan cabang akan berkurang. Jika tidak, ini mungkin mengindikasikan bahwa tes tidak diperlukan, karena jalur sudah dicakup oleh tes lain.
Apakah Anda hanya menguji kode yang harus Anda uji? Anda tidak diharapkan untuk menguji kerangka kerja yang mendasari perpustakaan pihak ketiga, tetapi secara eksklusif kode proyek itu sendiri.
Dengan tes asap, tes sistem dan integrasi, tes fungsional dan penerimaan, serta tes stres dan beban, Anda menambahkan lebih banyak kode uji, sehingga memiliki empat atau lima LOC tes untuk setiap LOC kode aktual bukanlah sesuatu yang harus Anda khawatirkan.
Catatan tentang TDD
Jika Anda khawatir tentang waktu yang diperlukan untuk menguji kode Anda, mungkin Anda melakukan kesalahan, itu kode pertama, tes nanti. Dalam hal ini, TDD dapat membantu dengan mendorong Anda untuk bekerja dalam iterasi 15-45 detik, beralih antara kode dan tes. Menurut para pendukung TDD, itu mempercepat proses pengembangan dengan mengurangi baik jumlah tes yang perlu Anda lakukan dan, yang lebih penting, jumlah kode bisnis untuk menulis dan terutama menulis ulang untuk pengujian.
¹ Biarkan n menjadi panjang maksimal string . Kita dapat memanggil
SayHello
dan mengirim referensi panjang string n - 1 yang seharusnya bekerja dengan baik. Sekarang, padaConsole.WriteLine
langkah, format harus berakhir dengan string dengan panjang n + 8, yang akan menghasilkan pengecualian. Mungkin, karena batas memori, bahkan string yang berisi n / 2 karakter akan menghasilkan pengecualian. Pertanyaan yang harus ditanyakan adalah apakah tes keempat ini adalah unit test (sepertinya tes satu, tetapi mungkin memiliki dampak yang jauh lebih tinggi dalam hal sumber daya dibandingkan dengan tes unit rata-rata) dan jika tes ini kode aktual atau kerangka kerja yang mendasarinya.sumber
personName
cocok dalam astring
, tetapi nilaipersonName
ditambah nilai-nilai gabungan melimpahstring
.As a rule of thumb, if you remove a unit test, the branch coverage should decrease.
Jika saya menulis keempat tes yang Anda sebutkan di atas, dan kemudian menghapus tes ke-3, apakah cakupannya akan berkurang?Saya pikir penting untuk membedakan antara dua jenis strategi pengujian: pengujian unit dan pengujian integrasi / penerimaan.
Meskipun pengujian unit diperlukan dalam beberapa kasus, ini sering dilakukan tanpa harapan. Ini diperburuk oleh metrik yang tidak berarti yang dipaksakan pada pengembang, seperti "cakupan 100%". http://www.rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf memberikan argumen yang meyakinkan untuk ini. Pertimbangkan masalah berikut dengan pengujian unit agresif:
Pengujian integrasi / penerimaan, di sisi lain, adalah bagian yang sangat penting dari kualitas perangkat lunak, dan dalam pengalaman saya Anda harus menghabiskan banyak waktu untuk memperbaikinya.
Banyak toko yang meminum bantuan kool TDD, tetapi seperti yang ditunjukkan oleh tautan di atas, sejumlah penelitian menunjukkan bahwa manfaatnya tidak dapat disimpulkan.
sumber
.equals()
metode panjang yang dihasilkan oleh Eclipse." Saya menulis uji harness untukequals()
dancompareTo()
github.com/GlenKPeterson/TestUtils Hampir setiap implementasi yang pernah saya uji kurang. Bagaimana Anda menggunakan koleksi jikaequals()
danhashCode()
tidak bekerja bersama dengan benar dan efisien? Saya bersorak lagi untuk sisa jawaban Anda dan telah memilihnya. Saya bahkan mengakui bahwa beberapa metode yang dihasilkan secara otomatis sama dengan () mungkin tidak perlu pengujian, tetapi saya sudah memiliki banyak bug dengan implementasi yang buruk sehingga membuat saya gugup.Tidak bisa digeneralisasi.
Jika saya perlu menerapkan formula atau algoritma dari rendering berbasis fisik, bisa jadi saya menghabiskan 10 jam pada tes unit paranoid, karena saya tahu sedikit bug atau keputusan dapat menyebabkan bug yang hampir mustahil untuk didiagnosis, beberapa bulan kemudian .
Jika saya hanya ingin secara logis mengelompokkan beberapa baris kode dan memberikannya nama, hanya digunakan dalam lingkup file, saya mungkin tidak mengujinya sama sekali (jika Anda bersikeras menulis tes untuk setiap fungsi tunggal, tanpa kecuali, programmer dapat mundur kembali untuk menulis fungsi sesedikit mungkin).
sumber
Ya, itu normal jika Anda berbicara tentang TDDing. Ketika Anda memiliki tes otomatis, Anda mengamankan perilaku kode yang diinginkan. Saat Anda menulis tes terlebih dahulu, Anda menentukan apakah kode yang ada sudah memiliki perilaku yang Anda inginkan.
Ini berarti:
(Ini tidak memperhitungkan refactoring kode, yang bertujuan menghabiskan lebih sedikit waktu untuk menulis kode berikutnya. Diseimbangkan dengan tes refactoring, yang bertujuan menghabiskan lebih sedikit waktu untuk menulis tes berikutnya.)
Ya juga jika Anda berbicara tentang menulis tes setelah fakta, maka Anda akan menghabiskan lebih banyak waktu:
Daripada Anda akan menghabiskan benar-benar menulis kode.
Jadi ya, itu adalah ukuran yang diharapkan.
sumber
Saya menemukan itu menjadi bagian terpenting.
Pengujian unit tidak selalu tentang "melihat apakah itu bekerja dengan benar", ini tentang belajar. Setelah Anda cukup menguji sesuatu, itu menjadi "hardcode" ke dalam otak Anda dan Anda akhirnya menurunkan waktu pengujian unit Anda dan dapat menemukan diri Anda menulis seluruh kelas dan metode tanpa menguji apa pun sampai selesai.
Inilah sebabnya mengapa salah satu jawaban lain pada halaman ini menyebutkan bahwa dalam "kursus" mereka melakukan pengujian 90%, karena semua orang perlu mempelajari peringatan dari tujuan mereka.
Pengujian unit bukan hanya penggunaan waktu Anda yang sangat berharga karena benar-benar meningkatkan keterampilan Anda, ini adalah cara yang baik untuk memeriksa kode Anda sendiri lagi dan menemukan kesalahan logis di sepanjang jalan.
sumber
Itu bisa untuk banyak orang, tetapi itu tergantung.
Jika Anda menulis tes terlebih dahulu (TDD), Anda mungkin mengalami beberapa tumpang tindih dalam waktu yang dihabiskan untuk menulis tes ini sebenarnya membantu untuk menulis kode. Mempertimbangkan:
Saat menulis tes setelah menulis kode, Anda mungkin menemukan kode Anda tidak mudah diuji, sehingga tes menulis lebih sulit / lebih lama.
Sebagian besar programmer telah menulis kode lebih lama daripada tes, jadi saya berharap sebagian besar dari mereka tidak lancar. Plus Anda bisa menambahkan waktu yang diperlukan untuk memahami dan memanfaatkan kerangka pengujian Anda.
Saya pikir kita perlu mengubah pola pikir kita tentang berapa lama waktu yang dibutuhkan untuk kode dan bagaimana unit testing terlibat. Jangan pernah melihatnya dalam jangka pendek dan tidak pernah hanya membandingkan total waktu untuk memberikan fitur tertentu karena Anda harus mempertimbangkan tidak hanya Anda menulis kode yang lebih baik / kurang kereta, tetapi kode yang lebih mudah untuk diubah dan tetap membuatnya lebih baik / kurang buggy.
Pada titik tertentu, kita semua hanya mampu menulis kode yang begitu bagus, sehingga beberapa alat dan teknik hanya dapat menawarkan begitu banyak dalam meningkatkan keterampilan kita. Bukannya aku bisa membangun rumah jika aku hanya punya gergaji laser.
sumber
Ya itu. Dengan beberapa peringatan.
Pertama-tama, adalah "normal" dalam arti bahwa sebagian besar toko besar bekerja dengan cara ini, jadi meskipun cara ini sepenuhnya salah arah dan bodoh, tetap saja, fakta bahwa sebagian besar toko besar bekerja dengan cara ini menjadikannya "normal".
Dengan ini saya tidak bermaksud mengatakan bahwa pengujian itu salah. Saya telah bekerja di lingkungan tanpa pengujian, dan di lingkungan dengan pengujian obsesif-kompulsif, dan saya masih bisa memberi tahu Anda bahwa bahkan pengujian obsesif-kompulsif lebih baik daripada tanpa pengujian.
Dan saya belum melakukan TDD, (siapa tahu, saya mungkin di masa depan), tetapi saya melakukan sebagian besar siklus edit-run-debug dengan menjalankan tes, bukan aplikasi yang sebenarnya, jadi tentu saja, saya bekerja banyak pada tes saya, sehingga untuk menghindari sebanyak mungkin harus menjalankan aplikasi yang sebenarnya.
Namun, perlu diketahui bahwa ada bahaya dalam pengujian yang berlebihan, dan khususnya dalam jumlah waktu yang dihabiskan untuk mempertahankan tes. (Saya terutama menulis jawaban ini untuk secara khusus menunjukkan hal ini.)
Dalam pengantar The Art of Unit Testing karya Roy Osherove (Manning, 2009) penulis mengakui telah berpartisipasi dalam proyek yang gagal sebagian besar karena beban pengembangan yang luar biasa yang ditimbulkan oleh tes unit yang dirancang dengan buruk yang harus dipertahankan sepanjang tahun. durasi upaya pengembangan. Jadi, jika Anda mendapati diri Anda menghabiskan terlalu banyak waktu hanya melakukan tes, ini tidak berarti Anda berada di jalur yang benar, karena itu "normal". Upaya pengembangan Anda mungkin telah memasuki mode tidak sehat, di mana pemikiran ulang radikal terhadap metodologi pengujian Anda mungkin diperlukan untuk menyelamatkan proyek.
sumber
sumber