Rasa unit test tanpa TDD

28

Kami memiliki proyek baru (cukup besar) yang mulai, yang kami rencanakan untuk dikembangkan menggunakan TDD.

Gagasan TDD gagal (banyak alasan bisnis dan non-bisnis), tetapi saat ini kami memiliki percakapan - haruskah kami menulis unit test, atau tidak. Teman saya mengatakan bahwa tidak ada (atau hampir nol) akal dalam menulis tes unit tanpa TDD, kita harus fokus hanya pada tes integrasi. Saya percaya sebaliknya, bahwa masih ada beberapa pengertian dalam menulis tes unit biasa, hanya untuk membuat kode lebih futureproof. Apa yang kamu pikirkan?

Ditambahkan: Saya pikir ini bukan duplikat >> pertanyaan ini << - Saya mengerti perbedaan antara UT dan TDD. Pertanyaan saya bukan tentang perbedaan , tetapi tentang rasa menulis Tes Unit tanpa TDD.

ex3v
sumber
22
Saya ingin tahu apa alasan teman Anda memiliki sikap yang tidak masuk akal ...
Telastyn
11
Saya bertaruh bahwa sebagian besar proyek dengan beberapa unit test tidak menggunakan TDD.
Casey
2
Apa yang akan menjadi tingkat integrasi Anda? Apa yang akan menjadi unit Anda? Seberapa sering Anda akan refactoring di bawah setiap level tes? Seberapa cepat tes integrasi Anda akan berjalan? Seberapa mudah mereka menulis? Berapa banyak kasus kombinatorial yang dihasilkan berbagai bagian kode Anda? dll ... Jika Anda tidak tahu jawabannya, maka mungkin masih terlalu dini untuk membuat keputusan tegas. Terkadang TDD bagus. Terkadang manfaatnya kurang jelas. Terkadang tes unit sangat penting. Kadang-kadang satu set tes integrasi yang layak memberi Anda hampir sama banyak, dan jauh lebih fleksibel ... Biarkan opsi Anda tetap terbuka.
topo Reinstate Monica
2
Sebagai saran praktis dari pengalaman, jangan menguji semuanya jika Anda tidak melakukan TDD. Tentukan tekad tentang jenis tes apa yang berharga. Saya telah menemukan bahwa pengujian unit pada metode input / output murni sangat berharga, sementara tes integrasi pada tingkat aplikasi yang sangat tinggi (mis., Benar-benar mengirimkan permintaan web pada aplikasi web) juga sangat berharga. Berhati-hatilah dengan tes integrasi mid-tier dan tes unit yang membutuhkan banyak tiruan. Tonton juga video ini: youtube.com/watch?v=R9FOchgTtLM .
jpmc26
Pembaruan Anda tidak masuk akal sehubungan dengan pertanyaan yang Anda ajukan. Jika Anda memahami perbedaan antara Tes TDD dan Unit, maka apa yang menahan Anda dari penulisan tes unit. Voting untuk menutup pertanyaan Anda meskipun saya bisa melihat argumen untuk menutup sebagai "tidak jelas tentang apa yang Anda minta" bukannya duplikat.

Jawaban:

52

TDD digunakan terutama (1) untuk memastikan cakupan, (2) dan untuk mendorong desain yang dapat dipertahankan, dimengerti, dan dapat diuji. Jika Anda tidak menggunakan TDD, Anda tidak mendapatkan cakupan kode yang dijamin.Tapi itu sama sekali tidak berarti bahwa Anda harus meninggalkan tujuan itu dan hidup bahagia dengan cakupan 0%.

Tes regresi diciptakan karena suatu alasan. Alasannya adalah bahwa dalam jangka panjang, mereka menghemat lebih banyak waktu Anda dalam kesalahan yang dicegah daripada mengambil upaya tambahan untuk menulis. Ini telah terbukti berulang kali. Oleh karena itu, kecuali jika Anda serius yakin bahwa organisasi Anda jauh, jauh lebih baik di rekayasa perangkat lunak dari semua guru yang merekomendasikan pengujian regresi (atau jika Anda berencana akan turun segera sehingga ada yang tidak lama berjalan untuk Anda), ya, Anda harus benar-benar memiliki unit test, untuk alasan persis yang berlaku untuk hampir setiap organisasi lain di dunia: karena mereka menangkap kesalahan lebih awal daripada tes integrasi, dan itu akan menghemat uang Anda. Tidak menulis mereka seperti melewatkan uang gratis hanya berbaring di jalan.

Kilian Foth
sumber
12
"Jika Anda tidak menggunakan TDD, Anda tidak mendapatkan jaminan kode cakupan.": Saya rasa tidak. Anda dapat mengembangkan selama dua hari, dan selama dua hari berikutnya Anda menulis tes. Poin penting adalah bahwa Anda tidak mempertimbangkan fitur selesai sampai Anda memiliki cakupan kode yang diinginkan.
Giorgio
5
@DougM - Di dunia yang ideal mungkin ...
Telastyn
7
Sayangnya TDD berjalan seiring dengan mengejek dan sampai orang berhenti melakukan itu semua membuktikan bahwa tes Anda berjalan lebih cepat . TDD sudah mati. Pengujian langsung panjang.
MickyD
17
TDD tidak menjamin cakupan kode. Itu asumsi yang berbahaya. Anda dapat membuat kode terhadap tes, lulus tes tersebut, tetapi masih memiliki kasus tepi.
Robert Harvey
4
@MickyDuncan Saya tidak yakin saya sepenuhnya memahami keprihatinan Anda. Mengejek adalah teknik yang benar-benar valid yang digunakan untuk mengisolasi satu komponen dari yang lain sehingga tes perilaku komponen itu dapat dilakukan secara independen. Ya, jika terlalu ekstrem, hal itu dapat mengarah ke perangkat lunak yang direkayasa berlebihan, tetapi demikian juga teknik pengembangan apa pun jika digunakan secara tidak tepat. Selain itu, seperti yang dinyatakan oleh DHH dalam artikel yang Anda kutip, gagasan untuk hanya menggunakan tes sistem lengkap sama buruknya, jika tidak benar-benar lebih buruk. Penting untuk menggunakan penilaian untuk memutuskan apa cara terbaik untuk menguji fitur tertentu .
Jules
21

Saya memiliki anekdot yang relevan dari sesuatu yang sedang terjadi saat ini untuk saya. Saya sedang mengerjakan proyek yang tidak menggunakan TDD. Orang-orang QA kami menggerakkan kami ke arah itu, tapi kami pakaian kecil dan itu merupakan proses yang panjang dan berlarut-larut.

Bagaimanapun , saya baru-baru ini menggunakan perpustakaan pihak ketiga untuk melakukan tugas tertentu. Ada masalah tentang penggunaan perpustakaan itu, jadi pada dasarnya saya harus menulis versi dari perpustakaan yang sama itu sendiri. Secara total, itu berakhir menjadi sekitar 5.000 baris kode yang dapat dieksekusi dan sekitar 2 bulan waktu saya. Saya tahu baris kode adalah metrik yang buruk, tetapi untuk jawaban ini saya merasa ini adalah indikator yang cukup baik.

Ada satu struktur data tertentu yang saya butuhkan yang akan memungkinkan saya untuk melacak jumlah bit yang sewenang-wenang. Karena proyek ini di Jawa, saya memilih Java BitSetdan memodifikasinya sedikit (saya membutuhkan kemampuan untuk melacak yang terkemuka 0juga, yang BitSet Java tidak lakukan untuk beberapa alasan .....). Setelah mencapai ~ 93% cakupan saya mulai menulis beberapa tes yang benar-benar akan menekankan sistem yang saya tulis. Saya perlu membandingkan aspek-aspek tertentu dari fungsionalitas untuk memastikan mereka cukup cepat untuk kebutuhan akhir saya. Tidak mengherankan, salah satu fungsi yang saya timpa dari BitSetantarmuka adalah sangat lambat ketika berurusan dengan set bit besar (ratusan juta bit dalam kasus ini). Fungsi yang diganti lainnya bergantung pada fungsi yang satu ini, jadi itu sangat besar leher botol yang .

Apa yang akhirnya saya lakukan adalah pergi ke papan gambar, dan mencari cara untuk memanipulasi struktur yang mendasari BitSet, yang merupakanlong[] . Saya merancang algoritme, meminta masukan dari kolega, dan kemudian saya mulai menulis kode. Kemudian, saya menjalankan tes unit. Beberapa dari mereka rusak, dan yang menunjuk saya tepat ke tempat saya perlu mencari di algoritma saya untuk memperbaikinya. Setelah memperbaiki semua kesalahan dari unit test, saya dapat mengatakan bahwa fungsinya berfungsi sebagaimana mestinya. Paling tidak, saya bisa yakin bahwa algoritma baru ini bekerja sebaik algoritma sebelumnya.

Tentu saja, ini bukan bukti peluru. Jika ada bug dalam kode saya yang tidak diperiksa oleh unit test, maka saya tidak akan mengetahuinya. Tapi tentu saja, bug yang sama persis itu bisa ada dalam algoritma saya yang lebih lambat juga. Namun , saya dapat mengatakan dengan tingkat kepercayaan yang tinggi bahwa saya tidak perlu khawatir tentang output yang salah dari fungsi tertentu. Tes unit yang sudah ada menyelamatkan saya berjam-jam, mungkin berhari-hari, mencoba menguji algoritma baru untuk memastikan itu benar.

Itu adalah titik memiliki unit test terlepas dari TDD - artinya, unit test akan melakukan ini untuk Anda dalam TDD dan di luar TDD semua sama, ketika Anda akhirnya refactoring / mempertahankan kode. Tentu saja, ini harus dipasangkan dengan pengujian regresi reguler, pengujian asap, pengujian fuzzy, dll, tetapi pengujian unit , seperti namanya, menguji hal-hal pada tingkat atom terkecil yang mungkin, yang memberi Anda arahan tentang di mana kesalahan muncul.

Dalam kasus saya, tanpa tes unit yang ada, entah bagaimana saya harus menemukan metode untuk memastikan algoritma bekerja sepanjang waktu. Yang, pada akhirnya ... terdengar sangat mirip dengan pengujian unit , bukan?

Shaz
sumber
7

Anda dapat membagi kode secara kasar menjadi 4 kategori:

  1. Perubahan sederhana dan jarang.
  2. Sederhana dan sering berubah.
  3. Kompleks dan jarang berubah.
  4. Kompleks dan sering berubah.

Tes unit menjadi lebih berharga (cenderung menangkap bug penting) semakin jauh ke bawah daftar Anda pergi. Dalam proyek pribadi saya, saya hampir selalu melakukan TDD pada kategori 4. Pada kategori 3 saya biasanya melakukan TDD kecuali pengujian manual lebih sederhana dan lebih cepat. Misalnya, kode antialiasing akan rumit untuk ditulis, tetapi jauh lebih mudah untuk memverifikasi secara visual daripada menulis unit test, jadi unit test hanya akan sepadan dengan saya jika kode itu sering berubah. Sisa kode saya hanya dimasukkan dalam unit test setelah saya menemukan bug dalam fungsi itu.

Terkadang sulit untuk mengetahui sebelumnya kategori apa yang cocok untuk suatu blok kode tertentu. Nilai TDD adalah Anda tidak sengaja melewatkan salah satu tes unit kompleks. Biaya TDD adalah semua waktu yang Anda habiskan untuk menulis tes unit sederhana. Namun, biasanya orang yang berpengalaman dengan suatu proyek tahu dengan tingkat kepastian yang masuk akal kategori apa yang cocok untuk berbagai bagian kode. Jika Anda tidak melakukan TDD, Anda setidaknya harus mencoba menulis tes yang paling berharga.

Karl Bielefeldt
sumber
1
Ketika mengerjakan kode seperti yang Anda sarankan dengan contoh antialiasing Anda, saya menemukan hal terbaik adalah mengembangkan kode secara eksperimental, kemudian menambahkan beberapa tes karakterisasi untuk memastikan bahwa saya tidak sengaja memecahkan algoritma nanti. Tes karakterisasi sangat cepat dan mudah dikembangkan, sehingga biaya overhead untuk melakukan ini sangat rendah.
Jules
1

Baik itu tes unit, komponen, integrasi atau penerimaan, bagian yang penting adalah bahwa itu harus otomatis. Tidak memiliki tes otomatis adalah kesalahan fatal untuk semua jenis perangkat lunak, dari CRUD sederhana hingga perhitungan paling kompleks. Alasannya adalah bahwa menulis tes otomatis akan selalu lebih murah daripada kebutuhan berkesinambungan untuk menjalankan semua tes secara manual ketika Anda tidak melakukannya, berdasarkan pesanan besarnya. Setelah Anda menulisnya, Anda hanya perlu menekan tombol untuk melihat apakah mereka lulus atau gagal. Tes manual akan selalu memakan waktu lama untuk dijalankan, dan bergantung pada manusia (makhluk hidup yang bosan, mungkin kurang perhatian dan sebagainya) untuk dapat memeriksa apakah tes lulus atau gagal. Singkatnya, selalu menulis tes otomatis.

Sekarang, tentang alasan mengapa kolega Anda mungkin menentang melakukan segala jenis pengujian unit tanpa TDD: Mungkin karena lebih sulit untuk mempercayai tes yang ditulis setelah kode produksi. Dan jika Anda tidak bisa mempercayai tes otomatis Anda, mereka layak apa-apa . Setelah siklus TDD, Anda harus terlebih dahulu membuat tes gagal (untuk alasan yang tepat) untuk diizinkan menulis kode produksi agar lulus (dan tidak lebih). Proses ini pada dasarnya menguji pengujian Anda, sehingga Anda dapat memercayainya. Belum lagi fakta bahwa menulis tes sebelum kode aktual mendorong Anda untuk merancang unit dan komponen Anda agar lebih mudah diuji (tingkat tinggi decoupling, penerapan SRP, dll ...). Meskipun, tentu saja, melakukan TDD membutuhkan disiplin .

Alih-alih, jika Anda menulis semua kode produksi terlebih dahulu, saat Anda menulis tes untuk itu, Anda akan mengharapkan mereka lulus pada menjalankan pertama. Ini sangat bermasalah, karena Anda mungkin telah membuat tes yang mencakup 100% kode produksi Anda, tanpa menyatakan perilaku yang benar (bahkan mungkin tidak melakukan pernyataan apa pun! Saya pernah melihat ini terjadi ), karena Anda tidak dapat melihatnya gagal pertama untuk memeriksa apakah gagal karena alasan yang tepat. Dengan demikian, Anda mungkin memiliki kesalahan positif. Positif palsu pada akhirnya akan merusak kepercayaan pada test suite Anda, pada dasarnya memaksa orang untuk melakukan pengujian manual lagi, sehingga Anda memiliki biaya untuk kedua proses tersebut (menulis tes + tes manual).

Ini berarti Anda harus menemukan cara lain untuk menguji tes Anda , seperti TDD. Jadi Anda menggunakan debugging, mengomentari bagian dari kode produksi, dll., Agar dapat mempercayai pengujian. Masalahnya adalah bahwa proses "menguji tes Anda" jauh lebih lambat dengan cara ini. Menambahkan waktu ini ke waktu yang akan Anda habiskan untuk menjalankan tes ad-hoc secara manual (karena Anda tidak memiliki tes otomatis saat Anda mengode kode produksi), menurut pengalaman saya, menghasilkan keseluruhan proses yang jauh lebih lambat daripada berlatih. TDD "by the book" (Kent Beck - TDD dengan Contoh). Juga, saya bersedia bertaruh di sini dan mengatakan bahwa benar-benar "menguji tes Anda" setelah ditulis membutuhkan lebih banyak disiplin daripada TDD.

Jadi mungkin tim Anda dapat mempertimbangkan kembali "alasan bisnis dan non-bisnis" untuk tidak melakukan TDD. Dalam pengalaman saya, orang cenderung berpikir TDD lebih lambat dibandingkan dengan hanya menulis tes unit setelah kode selesai. Asumsi ini cacat, seperti yang Anda baca di atas.

MichelHenrich
sumber
0

Seringkali kualitas tes tergantung pada asalnya. Saya secara teratur bersalah karena tidak melakukan TDD 'nyata' - Saya menulis beberapa kode untuk membuktikan bahwa strategi yang ingin saya gunakan benar-benar berfungsi, kemudian membahas setiap kasus bahwa kode dimaksudkan untuk mendukung dengan tes sesudahnya. Biasanya unit kode adalah kelas, untuk memberi Anda gambaran umum tentang berapa banyak pekerjaan yang akan saya lakukan dengan senang hati tanpa cakupan tes - artinya, bukan jumlah yang besar. Apa artinya ini adalah bahwa makna semantik dari tes cocok dengan baik dengan sistem yang diuji dalam keadaan 'selesai' - karena saya menulis mereka mengetahui kasus-kasus apa yang dipenuhi oleh SUT dan bagaimana hal itu memenuhi mereka.

Sebaliknya, TDD dengan kebijakan refactoring agresif cenderung membuat tes usang setidaknya secepat Anda dapat menuliskannya sebagai antarmuka publik sistem yang sedang diuji perubahan. Secara pribadi saya menemukan beban kerja mental baik merancang unit fungsional aplikasi dan menjaga semantik tes yang menyelaraskannya menjadi terlalu tinggi untuk mempertahankan konsentrasi saya dan pemeliharaan tes sering tergelincir. Basis kode berakhir dengan tes berkeliaran yang tidak menguji sesuatu yang bernilai atau hanya salah. Jika Anda memiliki kedisiplinan dan kapasitas mental untuk tetap mengikuti test suite, tentu saja, praktikkan TDD seketat yang Anda inginkan. Saya tidak, jadi saya merasa kurang berhasil karena alasan itu.

Tom W
sumber
0

Sebenarnya Paman Bob menyebutkan hal yang sangat menarik di salah satu video Clean Coders-nya. Dia mengatakan bahwa siklus Red-Green-Refactor dapat diterapkan dalam 2 cara.

1 adalah cara TDD konvensional. Tulis tes yang gagal lalu buat lulus ujian dan akhirnya refactor.

Cara kedua adalah dengan menulis kode produksi yang sangat kecil dan segera ikuti dengan unit test lalu refactor.

Idenya adalah untuk pergi dalam langkah - langkah yang sangat kecil . Tentu saja Anda kehilangan verifikasi dari kode produksi bahwa pengujian Anda berubah dari merah menjadi hijau, tetapi dalam beberapa kasus di mana saya bekerja sebagian besar dengan pengembang junior yang menolak bahkan untuk mencoba memahami TDD ternyata terbukti agak efektif.

Sekali lagi saya ulangi (dan ini ditekankan oleh Paman Bob) idenya adalah untuk pergi dalam langkah-langkah yang sangat kecil dan untuk segera menguji potongan kode produksi yang baru saja ditambahkan.

Songo
sumber
"... idenya adalah untuk pergi dalam langkah-langkah yang sangat kecil dan untuk segera menguji potongan kode produksi yang baru saja ditambahkan.": Saya tidak setuju. Apa yang Anda gambarkan jika bagus ketika Anda sudah memiliki gagasan yang jelas tentang apa yang ingin Anda lakukan dan Anda ingin mengerjakan detailnya, tetapi Anda harus mendapatkan gambaran besarnya terlebih dahulu. Kalau tidak, dengan melakukan langkah-langkah yang sangat kecil (menguji, mengembangkan, menguji, mengembangkan) Anda bisa tersesat dalam detail. "Jika kamu tidak tahu kemana kamu pergi, kamu mungkin tidak akan sampai di sana."
Giorgio