it-swarm-id.com

Mengapa TDD berfungsi?

Pengembangan berdasarkan uji coba (TDD) besar hari ini. Saya sering melihatnya direkomendasikan sebagai solusi untuk berbagai masalah di sini di Programmer SE dan tempat lainnya. Saya bertanya-tanya mengapa ini berhasil.

Dari sudut pandang teknik, saya bingung karena dua alasan:

  1. Pendekatan "tulis tes + refactor sampai lulus" terlihat sangat anti-rekayasa. Jika insinyur sipil menggunakan pendekatan itu untuk pembangunan jembatan, atau perancang mobil untuk mobil mereka, misalnya, mereka akan membentuk kembali jembatan atau mobil mereka dengan biaya yang sangat tinggi, dan hasilnya akan menjadi kekacauan yang diperbaiki tanpa arsitektur yang dipikirkan dengan matang. . Pedoman "refactor till pass" sering diambil sebagai mandat untuk melupakan desain arsitektur dan melakukan apa pun yang diperlukan untuk mematuhi tes; dengan kata lain, tes, bukan pengguna, yang menetapkan persyaratan. Dalam situasi ini, bagaimana kita bisa menjamin "kemampuan" yang baik dalam hasil, yaitu hasil akhir yang tidak hanya benar tetapi juga dapat diperluas, kuat, mudah digunakan, dapat diandalkan, aman, aman, dll.? Inilah yang biasanya dilakukan arsitektur.
  2. Pengujian tidak dapat menjamin bahwa suatu sistem berfungsi; itu hanya dapat menunjukkan bahwa itu tidak. Dengan kata lain, pengujian mungkin menunjukkan kepada Anda bahwa suatu sistem mengandung cacat jika gagal dalam suatu pengujian, tetapi suatu sistem yang lulus semua pengujian tidak lebih aman daripada sistem yang gagal. Cakupan tes, kualitas tes, dan faktor lainnya sangat penting di sini. Perasaan aman palsu yang dihasilkan oleh "semua hijau" hasil bagi banyak orang telah dilaporkan dalam industri sipil dan luar angkasa sebagai sangat berbahaya, karena dapat ditafsirkan sebagai "sistem baik-baik saja", ketika itu benar-benar berarti "sistem sama baiknya" sebagai strategi pengujian kami ". Seringkali, strategi pengujian tidak dicentang. Atau, siapa yang menguji tes?

Singkatnya, saya lebih peduli tentang bit "drive" dalam TDD daripada tentang bit "test". Pengujian sepenuhnya OK; yang tidak saya dapatkan adalah menggerakkan desain dengan melakukannya.

Saya ingin melihat jawaban yang berisi alasan mengapa TDD dalam rekayasa perangkat lunak adalah praktik yang baik, dan mengapa masalah yang saya jelaskan di atas tidak relevan (atau tidak cukup relevan) dalam kasus perangkat lunak. Terima kasih.

93
CesarGon

Saya pikir ada satu kesalahpahaman di sini. Dalam desain perangkat lunak, desainnya sangat dekat dengan produk. Dalam teknik sipil, arsitektur, desain dipisahkan dari produk yang sebenarnya: ada cetak biru yang menahan desain, yang kemudian terwujud menjadi produk jadi, dan mereka dipisahkan oleh sejumlah besar waktu dan usaha.

TDD sedang menguji desain. Tetapi setiap desain mobil dan desain bangunan juga diuji. Teknik konstruksi pertama kali dihitung, kemudian diuji dalam skala yang lebih kecil, kemudian diuji dalam skala yang lebih besar, sebelum dimasukkan ke dalam bangunan nyata. Ketika mereka menemukan balok-H dan beban misalnya, yakinlah bahwa ini telah dicoba dan dicoba lagi sebelum mereka benar-benar membangun jembatan pertama dengannya.

Desain mobil juga diuji, dengan merancang prototipe, dan ya, tentu dengan menyesuaikan hal-hal yang tidak sepenuhnya benar, hingga memenuhi harapan. Namun bagian dari proses ini lebih lambat, karena seperti yang Anda katakan, Anda tidak bisa dipusingkan dengan produk. Tetapi setiap desain ulang mobil mengacu pada pengalaman yang dipelajari dari yang sebelumnya, dan setiap bangunan memiliki sekitar seribu tahun fundamental di belakangnya tentang pentingnya ruang, cahaya, isolasi, kekuatan, dll. Rincian diubah dan ditingkatkan, baik di gedung-gedung dan dalam mendesain ulang untuk yang lebih baru.

Juga, bagian diuji. Mungkin tidak persis dalam gaya yang sama dengan perangkat lunak, tetapi bagian-bagian mekanik (roda, penyala, kabel) biasanya diukur dan ditekan untuk mengetahui ukurannya benar, tidak ada kelainan yang terlihat, dll. Mereka mungkin xrayed atau laser- diukur, mereka mengetuk batu bata untuk menemukan yang rusak, mereka mungkin benar-benar diuji dalam beberapa konfigurasi atau lainnya, atau mereka menggambar representasi terbatas kelompok besar untuk benar-benar mengujinya.

Itu semua hal yang bisa Anda lakukan dengan TDD.

Dan memang, pengujian bukanlah jaminan. Program macet, mobil mogok, dan bangunan mulai melakukan hal-hal lucu ketika angin bertiup. Tapi ... 'keamanan' bukan pertanyaan boolean. Bahkan ketika Anda tidak bisa memasukkan semuanya, mampu meliput - katakanlah - 99% kemungkinan lebih baik daripada hanya mencakup 50%. Tidak menguji dan kemudian mengetahui bahwa baja itu tidak beres dengan baik dan rapuh dan pecah pada pukulan pertama dari palu ketika Anda hanya memasang struktur utama Anda adalah buang-buang uang. Bahwa ada kekhawatiran lain yang mungkin masih menyakiti bangunan tidak membuatnya kurang bodoh untuk membiarkan cacat yang mudah dicegah menjatuhkan desain Anda.

Mengenai praktik TDD, itu adalah masalah keseimbangan. Biaya melakukannya satu arah (misalnya, tidak menguji, dan kemudian mengambil potongan nanti), dibandingkan biaya melakukannya dengan cara lain. Itu selalu keseimbangan. Tetapi jangan berpikir bahwa proses desain lainnya tidak memiliki pengujian dan TDD di tempat.

66
Inca

IMO, sebagian besar kisah sukses untuk TDD adalah palsu dan hanya untuk tujuan pemasaran. Mungkin ada sedikit keberhasilan dengan itu, tetapi hanya untuk aplikasi kecil. Saya sedang mengerjakan aplikasi silverlight besar di mana prinsip TDD digunakan. Aplikasi sudah mendapat ratusan tes tetapi masih belum stabil. Beberapa bagian dari aplikasi tidak dapat diuji karena interaksi pengguna yang kompleks. Menghasilkan tes dengan banyak ejekan dan sulit untuk memahami kode.

Awalnya ketika kami mencoba TDD, semuanya tampak baik. Saya bisa menulis banyak tes dan mengejek bagian-bagian yang sulit untuk unit test. Setelah Anda memiliki cukup banyak kode dan perubahan antarmuka diperlukan, Anda dikacaukan. Banyak tes yang harus diperbaiki dan Anda akan menulis ulang lebih banyak tes daripada perubahan kode yang sebenarnya.

Peter Norvig Menjelaskan pandangannya tentang TDD dalam buku Coders At Work.

Seibel: Bagaimana dengan gagasan menggunakan tes untuk mendorong desain?

Norvig: Saya melihat tes lebih sebagai cara untuk memperbaiki kesalahan daripada sebagai cara desain. Pendekatan ekstrem ini mengatakan, "Ya, hal pertama yang Anda lakukan adalah menulis tes yang mengatakan saya mendapatkan jawaban yang benar di akhir," dan kemudian Anda menjalankannya dan melihat bahwa itu gagal, dan kemudian Anda berkata, "Apa yang saya lakukan perlu berikutnya? ”- itu sepertinya bukan cara yang tepat untuk merancang sesuatu untuk saya. Sepertinya hanya jika itu sangat sederhana sehingga solusinya sudah ditakdirkan akan masuk akal. Saya pikir Anda harus memikirkannya terlebih dahulu. Anda harus mengatakan, “Apa saja bagiannya? Bagaimana saya bisa menulis tes untuk beberapa bagian sampai saya tahu apa itu? " Dan kemudian, setelah Anda selesai melakukannya, maka itu adalah disiplin yang baik untuk memiliki tes untuk masing-masing bagian dan untuk memahami dengan baik bagaimana mereka berinteraksi satu sama lain dan dengan kasus batas dan sebagainya. Mereka semua harus menjalani tes. Tapi saya tidak berpikir Anda mengendarai seluruh desain dengan mengatakan, "Tes ini telah gagal."

26
Navaneeth K N

Design Driven Design berfungsi untuk saya karena alasan berikut:

Ini adalah bentuk spesifikasi runnable.

Ini berarti bahwa Anda dapat melihat dari test case:

  1. [~ # ~] bahwa [~ # ~] kode yang dipanggil penuh memenuhi spesifikasi karena hasil yang diharapkan ada di sana dalam kasus uji. Inspeksi visual (yang mengharapkan kasus uji untuk lulus) dapat mengatakan langsung "oh, tes ini memeriksa bahwa perusahaan faktur panggilan mengingat situasi ini, harus memiliki hasil ITU".
  2. [~ # ~] bagaimana [~ # ~] kode harus dipanggil. Langkah-langkah aktual yang diperlukan untuk melakukan tes ditentukan secara langsung tanpa perancah eksternal (basis data dicemooh dll).

Anda yang menulis tampilan dari luar terlebih dahulu.

Kode yang sering ditulis dengan cara di mana Anda pertama menyelesaikan masalah, dan kemudian Anda memikirkan bagaimana kode yang baru saja Anda tulis dipanggil. Ini sering memberikan antarmuka yang canggung karena seringkali lebih mudah untuk "hanya menambahkan bendera" dll. Dengan berpikir "kita perlu melakukan INI sehingga testcases akan terlihat seperti ITU" di depan Anda membalikkan ini. Ini akan memberikan modularitas yang lebih baik, karena kode akan ditulis sesuai dengan antarmuka panggilan, bukan sebaliknya.

Ini biasanya akan menghasilkan kode pembersih juga yang memerlukan dokumentasi yang kurang jelas.

Anda selesai lebih cepat

Karena Anda memiliki spesifikasi pada formulir runnable, Anda selesai ketika suite tes lengkap berlalu. Anda dapat menambahkan lebih banyak tes saat Anda mengklarifikasi hal-hal pada tingkat yang lebih rinci, tetapi sebagai prinsip dasar Anda memiliki indikator kemajuan yang sangat jelas dan terlihat dan ketika Anda selesai.

Ini berarti bahwa Anda dapat mengetahui kapan pekerjaan diperlukan atau tidak (apakah itu membantu lulus ujian) Anda akhirnya perlu melakukan lebih sedikit.

Bagi mereka yang merenungkannya mungkin berguna bagi mereka, saya mendorong Anda untuk menggunakan TDD untuk rutin perpustakaan Anda berikutnya. Perlahan atur spesifikasi yang bisa dijalankan, dan buat kode lulus tes. Setelah selesai, spesifikasi runnable tersedia untuk semua orang yang perlu melihat cara menjalankan perpustakaan.

Penelitian baru-baru ini

"Hasil dari studi kasus menunjukkan bahwa kepadatan cacat pra-rilis dari empat produk menurun antara 40% dan 90% relatif terhadap proyek serupa yang tidak menggunakan praktik TDD. Subyektif, tim mengalami peningkatan 15 hingga 35% pada waktu pengembangan awal setelah mengadopsi TDD. " ~ Hasil dan Pengalaman 4 Tim Industri

25
user1249

Proses pembuatan perangkat lunak bukanlah proses penulisan kode. Tidak ada proyek perangkat lunak yang harus dimulai tanpa rencana 'cakupan luas' terlebih dahulu. Sama seperti proyek menjembatani dua tepi sungai, perlu rencana seperti itu terlebih dahulu.

Pendekatan TDD berhubungan (kebanyakan) dengan pengujian unit - setidaknya itulah cara orang cenderung memikirkannya - yaitu menciptakan bit kode perangkat lunak tingkat paling rendah. Ketika semua fitur dan perilaku telah didefinisikan dan kita benar-benar tahu apa yang ingin kita capai.

Dalam rekayasa struktural terlihat seperti ini:

'Kami memiliki dua keping logam yang dihubungkan bersama, dan sambungan perlu menopang gaya geser dalam urutan x. Mari kita coba metode koneksi mana yang terbaik untuk melakukan ini '

Untuk menguji apakah perangkat lunak bekerja secara keseluruhan, kami merancang jenis tes lain seperti tes kegunaan, tes integrasi dan tes penerimaan. Ini juga harus didefinisikan sebelum pekerjaan yang sebenarnya pada penulisan kode dimulai, dan dilakukan setelah unit test berwarna hijau.

Lihat V-Model: http://en.wikipedia.org/wiki/V-Model_%28software_development%29

Mari kita lihat cara kerjanya untuk jembatan:

  1. Pemerintah setempat mengatakan kepada perusahaan pembuat jembatan: "Kami membutuhkan jembatan untuk menghubungkan kedua titik ini. Jembatan harus dapat memungkinkan jumlah lalu lintas per jam dan siap untuk 21 Desember 2012 '- ini adalah definisi dari tes penerimaan. Perusahaan tidak akan mendapatkan jumlah penuh (atau apa pun) uang, jika mereka tidak dapat lulus tes itu.

  2. Manajemen perusahaan memutuskan jadwal proyek. Mereka membentuk tim kerja dan menetapkan tujuan untuk setiap tim. Jika tim tidak akan mencapai tujuan ini - jembatan tidak akan dibangun tepat waktu. Namun - ada beberapa tingkat fleksibilitas di sini. Jika salah satu tim memiliki beberapa masalah, perusahaan dapat mengimbangi itu dengan mengubah persyaratan, mengubah subkontraktor, merekrut lebih banyak orang, dll. Sehingga seluruh proyek masih memenuhi tujuan yang ditetapkan pada poin # 1.

  3. Di dalam tim yang bertanggung jawab untuk merancang komponen jembatan tertentu seperti pada contoh yang saya berikan di atas. Terkadang solusinya jelas, karena kami memiliki banyak pengetahuan tentang membangun jembatan (seperti menggunakan perpustakaan yang teruji dengan baik dalam pengembangan perangkat lunak - Anda hanya menganggap itu berfungsi seperti yang diiklankan). Terkadang Anda perlu membuat beberapa desain dan mengujinya untuk memilih yang terbaik. Namun, kriteria pengujian komponen diketahui sebelumnya.

19
Mchl

Dalam pikiran saya TDD berfungsi karena

  • Ini memaksa Anda menentukan apa yang Anda ingin unit lakukan sebelum memutuskan implementasi pada tingkat presisi yang umumnya tidak tercakup oleh dokumen spesifikasi atau persyaratan apa pun.
  • Itu membuat kode Anda secara inheren dapat digunakan kembali, karena Anda harus menggunakannya dalam skenario pengujian dan produksi
  • Ini mendorong Anda untuk menulis kode dalam eaiser yang lebih kecil untuk menguji potongan yang cenderung mengarah ke desain yang lebih baik

Khususnya pada poin yang Anda angkat

  • Kode lebih mudah dibentuk daripada bata atau baja, sehingga lebih murah untuk dimodifikasi. Masih lebih murah jika Anda memiliki tes untuk memastikan perilaku tidak berubah
  • TDD bukan alasan untuk tidak melakukan desain - arsitektur tingkat tinggi secara umum masih disarankan, hanya saja tidak dengan terlalu banyak detail. Desain Front Besar tidak dianjurkan, tetapi melakukan desain yang cukup dianjurkan
  • TDD tidak dapat menjamin suatu sistem berfungsi, tetapi mencegah banyak kesalahan kecil yang melewatinya jika tidak akan terlewatkan. Juga karena umumnya mendorong kode dengan faktor yang lebih baik, sering kali lebih mudah dipahami sehingga kecil kemungkinannya untuk buggy
18
Gavin Clarke

TL; DR

Pemrograman masih merupakan kegiatan desain, ini bukan konstruksi. Unit penulisan menguji setelah fakta hanya menegaskan bahwa kode melakukan apa yang dilakukannya, bukan bahwa ia melakukan sesuatu yang bermanfaat. Kegagalan tes adalah nilai sebenarnya karena mereka membiarkan Anda menangkap kesalahan lebih awal.

Desain Kode

Dalam Bab 7 dari PPP "Paman Bob" berbicara tentang masalah ini secara langsung. Sangat awal dalam bab ini, ia mereferensikan artikel yang bagus oleh Jack Reeves di mana ia mengusulkan bahwa kode itu dirancang (tautannya menuju ke halaman yang mengumpulkan ketiga artikelnya tentang topik tersebut).

Apa yang menarik tentang argumen ini adalah bahwa ia menunjukkan, tidak seperti disiplin teknik lainnya di mana konstruksi adalah kegiatan yang sangat mahal, konstruksi perangkat lunak relatif gratis (tekan kompilasi dalam IDE dan Anda telah membangun Jika Anda melihat penulisan kode sebagai aktivitas desain alih-alih aktivitas konstruksi, maka siklus merah-hijau-refraktor pada dasarnya adalah latihan dalam desain. Desain Anda berkembang saat Anda menulis tes, kode untuk memuaskan mereka, dan refactor untuk mengintegrasikan kode baru ke dalam sistem yang ada.

TDD sebagai Spesifikasi

Tes unit yang Anda tulis untuk TDD adalah terjemahan langsung dari spesifikasi yang Anda pahami. Dengan menulis kode yang minimal memenuhi spesifikasi Anda (membuat tes Anda berubah menjadi hijau), semua kode yang Anda tulis ada di sana untuk tujuan tertentu. Apakah tujuan itu telah dipenuhi atau belum divalidasi oleh tes yang berulang.

Tulis Tes untuk Fungsionalitas

Kesalahan umum dalam pengujian unit terjadi ketika Anda menulis tes setelah kode, Anda akhirnya menguji bahwa kode melakukan apa yang dilakukannya. Dengan kata lain Anda akan melihat tes seperti ini

public class PersonTest:Test
{
   [Test]
   TestNameProperty()
   {
      var person=new Person();
      person.Name="John Doe";
      Assert.AreEqual("John Doe", person.Name);
   }
}

Walaupun saya kira kode ini bisa berguna (pastikan seseorang belum melakukan sesuatu yang cabul dengan properti sederhana). Itu tidak berfungsi untuk memvalidasi spesifikasi. Dan seperti yang Anda katakan, menulis tes semacam ini hanya membawa Anda sejauh ini.

Sementara Hijau adalah Baik, Nilai Berada di Merah Saya memiliki momen "aha" pertama saya yang sebenarnya di TDD ketika saya mengalami kegagalan pengujian yang tidak terduga. Saya memiliki serangkaian tes yang saya miliki untuk kerangka kerja yang saya bangun. Menambahkan fitur baru, saya menulis tes untuk itu. Kemudian menulis kode untuk lulus ujian. Kompilasi, tes ... mendapat hijau pada tes baru. Tetapi juga mendapat merah pada tes lain yang saya tidak harapkan menjadi merah.

Melihat kegagalan itu, aku menghela nafas lega karena aku ragu aku akan menangkap serangga itu untuk beberapa waktu seandainya aku tidak menjalani tes itu. Dan itu adalah bug yang SANGAT jahat untuk dimiliki. Untungnya, saya telah melakukan tes, dan itu memberi tahu saya apa yang harus saya lakukan untuk memperbaiki bug. Tanpa tes, saya akan terus membangun sistem saya (dengan bug menginfeksi modul lain yang bergantung pada kode itu) dan pada saat bug ditemukan, itu akan menjadi tugas utama untuk memperbaikinya dengan benar.

Manfaat sebenarnya dari TDD adalah memungkinkan kita untuk membuat perubahan dengan mengabaikan sembrono. Ini seperti jaring pengaman untuk pemrograman. Pikirkan apa yang akan terjadi jika seorang seniman trapeze melakukan kesalahan dan jatuh. Dengan jaring, itu adalah kesalahan yang memalukan. Tanpa, itu adalah tragedi. Dalam hal yang sama, TDD menyelamatkan Anda dari mengubah kesalahan bertulang menjadi proyek yang membunuh bencana.

16
Michael Brown

Anda tidak akan menemukan siapa pun yang mendukung Pengembangan yang Didorong oleh Test, atau bahkan Test Driven Desain (mereka berbeda), yang mengatakan tes membuktikan aplikasi. Jadi mari kita sebut saja manusia jerami dan dilakukan.

Anda tidak akan menemukan orang yang tidak suka atau tidak terkesan oleh TDD yang mengatakan bahwa Tes adalah pemborosan waktu dan usaha. Meskipun tes tidak membuktikan aplikasi, mereka cukup membantu dalam menemukan kesalahan.

Dengan kedua hal tersebut, tidak ada pihak yang melakukan sesuatu yang berbeda sehubungan dengan benar-benar melakukan tes pada perangkat lunak. Keduanya sedang melakukan pengujian. Keduanya MENDAPATKAN pengujian untuk menemukan bug sebanyak mungkin, dan keduanya menggunakan tes untuk memverifikasi bahwa program perangkat lunak berfungsi dengan baik dan dapat ditemukan pada saat itu. Tidak seorang pun dengan setengah petunjuk menjual perangkat lunak tanpa pengujian dan tidak seorang pun dengan setengah petunjuk berharap bahwa pengujian akan membuat kode yang mereka jual benar-benar bebas bug.

Jadi, perbedaan antara TDD dan bukan-TDD bukanlah bahwa tes sedang dilakukan. Perbedaannya adalah ketika tes ditulis. Dalam tes TDD ditulis SEBELUM perangkat lunak. Bukan tes TDD ditulis setelah atau bersamaan dengan perangkat lunak.

Masalah yang saya lihat berkenaan dengan yang terakhir adalah bahwa pengujian kemudian cenderung menargetkan perangkat lunak yang ditulis lebih dari hasil atau spesifikasi yang diinginkan. Bahkan dengan tim pengujian terpisah dari tim pengembangan, tim pengujian cenderung melihat perangkat lunak, bermain dengannya, dan menulis tes yang menargetkannya.

Satu hal yang telah diperhatikan berkali-kali oleh mereka yang mempelajari kesuksesan proyek, adalah seberapa sering seorang pelanggan akan menata apa yang mereka inginkan, orang-orang pengembangan lari dan menulis sesuatu, dan ketika mereka kembali ke pelanggan mengatakan "selesai" ternyata benar-benar BUKAN apa yang diminta pelanggan. "Tapi itu melewati semua tes ..."

Tujuan TDD adalah untuk memecahkan "argumen melingkar" ini dan memberikan dasar untuk pengujian yang menguji perangkat lunak yang bukan perangkat lunak itu sendiri. Tes ditulis untuk menargetkan perilaku yang diinginkan oleh "pelanggan". Perangkat lunak ini kemudian ditulis untuk lulus tes tersebut.

TDD adalah bagian dari solusi yang dimaksudkan untuk mengatasi masalah ini. Itu bukan satu-satunya langkah yang Anda buat. Hal lain yang perlu Anda lakukan adalah memastikan ada lebih banyak umpan balik pelanggan dan lebih sering.

Namun dalam pengalaman saya, TDD adalah hal yang sangat sulit untuk berhasil diimplementasikan. Sulit untuk mendapatkan tes tertulis sebelum ada produk karena banyak pengujian otomatis memerlukan sesuatu untuk dimainkan agar perangkat lunak otomasi berfungsi dengan benar. Sulit juga untuk mendapatkan pengembang yang tidak terbiasa dengan pengujian unit untuk melakukannya. Berkali-kali saya memberi tahu orang-orang di tim saya untuk menulis tes PERTAMA. Saya tidak pernah benar-benar mendapatkannya untuk melakukannya. Pada akhirnya, kendala waktu dan politik menghancurkan semua upaya sehingga kita bahkan tidak melakukan tes unit sama sekali. Hal ini tentu saja mengarah, tak terhindarkan, pada desain yang secara tidak sengaja dan sangat berpasangan sehingga bahkan jika kita ingin, sekarang akan sangat mahal untuk diimplementasikan. Menghindari ITU adalah apa yang akhirnya disediakan TDD untuk pengembang.

11
Edward Strange

Desain dulu

TDD adalah tidak alasan untuk melewati desain. Saya telah melihat banyak lompatan dalam kereta musik "lincah" karena mereka meskipun mereka dapat mulai mengkodekan segera. Agile yang tangkas akan membuat Anda membuat kode stat lebih cepat daripada praktik bagus rekayasa (bidang lain) yang mengilhami proses air terjun.

Tapi tes awal

Ketika seseorang mengatakan bahwa tes tersebut mendorong desain, itu berarti bahwa seseorang dapat menggunakan tes sangat awal dalam fase desain, jauh sebelum itu selesai. Melakukan tes ini akan sangat mempengaruhi desain Anda dengan menantang area abu-abu dan mengadu domba itu dengan dunia nyata jauh sebelum produk selesai. memaksa Anda untuk sering kembali ke desain dan menyesuaikannya untuk memperhitungkan ini.

Uji dan desain ... satu dan sama

Menurut pendapat saya TDD hanya membawa pengujian menjadi integral bagian dari desain daripada sesuatu yang dilakukan pada akhirnya untuk memvalidasinya. Ketika Anda mulai menggunakan TDD semakin banyak Anda mendapatkan dalam pola pikir tentang bagaimana menghancurkan/menghancurkan sistem Anda saat Anda mendesainnya. Secara pribadi saya tidak selalu melakukan tes saya terlebih dahulu. Tentu saya melakukan tes (unit) yang jelas pada antarmuka tetapi keuntungan nyata berasal dari tes integrasi dan spesifikasi yang saya buat ketika saya memikirkan cara baru dan kreatif yang dapat dipecah oleh desain ini. Segera setelah saya memikirkan suatu cara, saya membuat kode tes untuk itu dan melihat apa yang terjadi. Terkadang saya dapat hidup dengan konsekuensinya, dalam hal ini saya memindahkan tes dalam proyek terpisah yang bukan bagian dari bangunan utama (karena akan terus gagal).

Lalu siapa yang mengemudikan pertunjukan?

Dalam TDD, penggerak di sini berarti bahwa pengujian Anda memengaruhi desain Anda dengan sangat kuat sehingga orang dapat merasakan bahwa mereka benar-benar mengendarainya. Namun itu berhenti di situ, dan di sini saya mengerti keprihatinan Anda, itu agak menakutkan ... yang mengemudikan pertunjukan?

ANDA mengemudi, bukan tes. Tes ada di sana sehingga ketika Anda bergerak maju Anda mendapatkan tingkat kepercayaan yang baik pada apa yang telah Anda buat sehingga memungkinkan Anda untuk membangun lebih lanjut dengan mengetahui bahwa itu didasarkan pada dasar yang kuat.

padat selama tes solid

Tepat, maka didorong dalam TDD. Bukan begitu banyak tes yang mengendalikan semuanya, tetapi mereka akan memiliki pengaruh yang begitu mendalam atas bagaimana Anda melakukan sesuatu, pada bagaimana Anda merancang dan berpikir sistem Anda sehingga Anda akan mendelegasikan sebagian besar dari proses pemikiran Anda untuk menguji dan sebagai imbalannya mereka akan memiliki pengaruh yang mendalam pada desain Anda.

ya tetapi jika saya melakukannya dengan jembatan saya ....

berhenti di sana ... rekayasa perangkat lunak SANGAT berbeda dari praktik rekayasa lainnya di luar sana. Sebenarnya rekayasa perangkat lunak sebenarnya memiliki lebih banyak kesamaan dengan literatur. Seseorang dapat mengambil buku yang sudah jadi, merobek 4 bab dari itu dan menulis dua bab baru untuk menggantikannya memasukkannya kembali ke dalam buku dan Anda masih memiliki buku yang bagus. Dengan pengujian dan perangkat lunak yang baik Anda dapat merobek bagian mana pun dari sistem Anda dan menggantinya dengan yang lain dan biaya untuk melakukannya tidak jauh lebih tinggi daripada yang diciptakannya. Bahkan, jika Anda melakukan tes dan membiarkannya mempengaruhi desain Anda, mungkin lebih murah daripada membuatnya di tempat pertama karena Anda akan memiliki tingkat kepercayaan tertentu bahwa penggantian ini tidak akan merusak apa yang dicakup tes.

Jika begitu bagus, kenapa tidak selalu berhasil?

Karena pengujian membutuhkan pola pikir yang SANGAT berbeda dari membangun. Tidak setiap orang dapat kembali dan dari sana, pada kenyataannya beberapa orang tidak akan dapat membangun tes yang tepat hanya karena mereka tidak dapat menetapkan pikiran mereka untuk menghancurkan ciptaan mereka. Ini akan menghasilkan proyek dengan terlalu sedikit pengujian atau pengujian yang cukup untuk mencapai metrik target (cakupan kode muncul di benak). Mereka akan senang tes jalur dan tes pengecualian tetapi akan melupakan kasus sudut dan kondisi batas.

Yang lain hanya akan bergantung pada tes desain yang akan datang sebagian atau seluruhnya. Setiap anggota melakukan hal itu kemudian berintegrasi dengan satu sama lain. Desain adalah alat komunikasi yang pertama dan terutama, taruhannya kami atur di tanah untuk mengatakan di sinilah saya akan berada, sketsa yang mengatakan ini adalah di mana pintu dan jendela akan berada. Tanpa ini, perangkat lunak Anda akan hancur terlepas dari berapa banyak tes yang Anda lakukan. Integrasi dan penggabungan akan selalu menyakitkan dan mereka akan kekurangan tes pada tingkat abstraksi tertinggi.

Untuk tim-tim ini, TDD mungkin bukan jalan yang harus ditempuh.

9
Newtopian

Dengan TDD Anda cenderung tidak menulis kode yang tidak mudah atau cepat untuk diuji. Ini mungkin tampak seperti hal kecil, tetapi dapat memiliki dampak mendalam pada proyek karena berdampak pada betapa mudahnya untuk melakukan refactor, menguji, mereproduksi bug dengan pengujian dan memverifikasi perbaikan.

Juga lebih mudah bagi pengembang baru di proyek untuk mempercepat ketika Anda memiliki kode faktor yang lebih baik didukung oleh tes.

7
Alb

Saya sudah banyak memikirkan hal ini, walaupun saya sendiri tidak terlalu banyak berlatih TDD. Tampaknya ada korelasi (kuat?) Positif antara kualitas kode dan mengikuti TDD.

1) Yang pertama saya ambil adalah, ini (terutama) bukan karena TDD menambahkan "kualitas yang lebih baik" ke dalam kode (seperti itu), itu lebih seperti TDD membantu menyingkirkan bagian dan kebiasaan terburuk, dan secara tidak langsung meningkatkan kualitas.

Saya bahkan akan menganjurkan bahwa itu bukan tes itu sendiri - itu adalah proses menulis tes-tes itu. Sulit untuk menulis tes untuk kode yang buruk, dan sebaliknya. Dan menjaga ini di belakang kepala saat pemrograman, menghilangkan banyak kode buruk.

2) Sudut pandang lain (ini semakin filosofis) adalah mengikuti kebiasaan mental tuannya. Anda tidak belajar menjadi seorang master dengan mengikuti "kebiasaan luar" -nya (seperti, janggut panjang itu baik), Anda harus belajar cara berpikir internalnya, dan ini sulit. Dan entah bagaimana membuat (pemula) programmer mengikuti TDD, menyelaraskan cara berpikir mereka lebih dekat dengan yang dimiliki master.

5
Maglob

Pendekatan "tulis tes + refactor sampai lulus" terlihat sangat anti-rekayasa.

Anda tampaknya memiliki kesalahpahaman tentang refactoring dan TDD.

Code refactoring adalah proses mengubah kode sumber program komputer tanpa mengubah perilaku fungsional eksternalnya untuk meningkatkan beberapa atribut nonfungsional dari perangkat lunak.

Dengan demikian Anda tidak dapat refactor kode sampai lewat.

Dan TDD, khususnya pengujian unit (yang saya anggap sebagai peningkatan inti, karena tes lain tampaknya agak masuk akal bagi saya), bukan tentang mendesain ulang komponen hingga berfungsi. Ini adalah tentang mendesain komponen dan bekerja pada implementasi hingga komponen berfungsi seperti yang dirancang.

Juga penting untuk benar-benar memahami, bahwa unit pengujian adalah tentang pengujian unit. Karena kecenderungan untuk selalu menulis banyak hal dari awal, penting untuk menguji unit tersebut. Seorang insinyur sipil sudah mengetahui spesifikasi unit yang ia gunakan (bahan yang berbeda) dan dapat mengharapkan mereka bekerja. Ini adalah dua hal yang sering tidak berlaku untuk insinyur perangkat lunak, dan sangat pro-teknik untuk menguji unit sebelum menggunakannya, karena itu berarti menggunakan komponen yang teruji dan berkualitas tinggi.
Jika seorang insinyur sipil memiliki ide untuk menggunakan beberapa jaringan serat baru untuk membuat atap untuk menutupi stadion, Anda akan mengharapkan dia untuk mengujinya sebagai sebuah unit, yaitu mendefinisikan spesifikasi yang diperlukan (misalnya berat, permeabilitas, stabilitas , dll.) dan setelah itu menguji dan memperbaikinya sampai memenuhi mereka.

Itu sebabnya TDD berfungsi. Karena jika Anda membuat perangkat lunak dari unit yang diuji, kemungkinannya jauh lebih baik, ketika Anda menyambungkannya dan jika tidak, Anda dapat mengharapkan masalah ada dalam kode lem Anda, dengan asumsi tes Anda memiliki cakupan yang baik.

sunting:
Refactoring berarti: no perubahan fungsionalitas. Salah satu titik pengujian unit penulisan adalah untuk memastikan, bahwa refactoring tidak melanggar kode. Jadi TDD dimaksudkan untuk memastikan, bahwa refactoring tidak memiliki efek samping.
Granularitas bukan subjek perspektif, karena seperti yang saya katakan, unit menguji unit tes dan bukan sistem, di mana granularitas didefinisikan secara tepat.

TDD mendorong arsitektur yang baik. Ini mengharuskan Anda untuk mendefinisikan dan mengimplementasikan spesifikasi untuk semua unit Anda, memaksa Anda untuk mendesainnya sebelum implementasi, yang sangat bertentangan dengan apa yang tampaknya Anda pikirkan. TDD menentukan pembuatan unit, yang dapat diuji secara individual dan dengan demikian sepenuhnya dipisahkan.
TDD tidak berarti saya melakukan tes perangkat lunak pada kode spageti dan mengaduk pasta sampai habis.

Dalam kontradiksi dengan teknik sipil, dalam rekayasa perangkat lunak suatu proyek biasanya terus berkembang. Dalam teknik sipil, Anda memiliki persyaratan untuk membangun jembatan di posisi A, yang dapat mengangkut x ton dan cukup lebar untuk n kendaraan per jam.
Dalam rekayasa perangkat lunak, pelanggan pada dasarnya dapat memutuskan pada titik mana pun (mungkin setelah selesai), ia menginginkan jembatan berlipat ganda, dan bahwa ia ingin jembatan itu terhubung dengan jalan raya terdekat, dan bahwa ia ingin jembatan itu diangkat sebagai pengangkat jembatan, karena perusahaannya baru-baru ini mulai menggunakan kapal layar.
Insinyur perangkat lunak ditugaskan untuk mengubah desain. Bukan karena desain mereka cacat, tetapi karena itu adalah modus operandi. Jika perangkat lunak direkayasa dengan baik, maka dapat dirancang ulang pada tingkat tinggi, tanpa harus menulis ulang semua komponen tingkat rendah.

TDD adalah tentang membangun perangkat lunak dengan komponen yang diuji secara terpisah dan sangat terpisah. Dikelola dengan baik, ini akan membantu Anda untuk merespons perubahan persyaratan secara signifikan lebih cepat dan lebih aman, daripada tanpa.

TDD menambahkan persyaratan untuk proses pengembangan, tetapi tidak melarang metode jaminan kualitas lainnya. Memang, TDD tidak menyediakan keamanan yang sama dengan verifikasi formal, tetapi sekali lagi, verifikasi formal sangat mahal dan tidak mungkin digunakan pada tingkat sistem. Dan tetap, jika Anda mau, Anda bisa menggabungkan keduanya.

TDD juga mencakup pengujian selain pengujian unit, yang dilakukan pada tingkat sistem. Saya menemukan ini mudah untuk dijelaskan tetapi sulit untuk dieksekusi dan sulit untuk diukur. Juga, mereka cukup masuk akal. Sementara saya benar-benar melihat kebutuhan mereka, saya tidak benar-benar menghargai mereka sebagai ide.

Pada akhirnya, tidak ada alat yang benar-benar memecahkan masalah. Alat hanya membuat pemecahan masalah lebih mudah. Anda dapat bertanya: Bagaimana pahat akan membantu saya dengan arsitektur yang hebat? Nah jika Anda berencana untuk melakukan dinding lurus, batu bata lurus sangat membantu. Dan ya, memang, jika Anda memberikan alat itu kepada orang idiot, ia mungkin akan membantingnya melalui kakinya pada akhirnya, tapi itu bukan kesalahan pahat, sebanyak itu bukan cacat TDD yang memberikan keamanan palsu kepada pemula, yang tidak menulis tes yang bagus.
Jadi pada intinya, dapat dikatakan bahwa TDD bekerja jauh lebih baik daripada tanpa TDD.

3
back2dos

Saya pikir Anda mendekati titik pertama dari sudut yang salah.

Dari sudut pandang teoretis, kami membuktikan bahwa sesuatu bekerja dengan memeriksa titik kegagalan. Itulah metode yang digunakan. Mungkin ada banyak cara lain Anda dapat membuktikan bahwa sesuatu itu fungsional, tetapi TDD telah memantapkan dirinya karena kesederhanaan dari pendekatan bit-bijaksana: jika tidak rusak itu berfungsi.

Dalam praktiknya, ini hanya secara terbuka diterjemahkan menjadi: kita sekarang dapat beralih ke hal berikutnya (setelah kita berhasil menerapkan TDD untuk memenuhi semua predikat). Jika Anda mendekati TDD dari perspektif ini, maka ini bukan tentang "tulis tes + refactor hingga lulus" ini lebih lanjut tentang setelah menyelesaikan ini, saya sekarang sepenuhnya berfokus pada fitur berikutnya sebagai yang paling sekarang yang penting .

Pikirkan bagaimana ini berlaku untuk teknik sipil. Kami sedang membangun stadion yang dapat menampung audiens publik 150000 orang. Setelah kami membuktikan bahwa integritas struktural stadion sehat, kami telah puas safety first. Kita sekarang dapat fokus pada isu-isu lain yang segera menjadi penting, seperti kamar kecil, kedai makanan, tempat duduk, dll ... menjadikan pengalaman penonton yang lebih menyenangkan. Ini adalah penyederhanaan yang berlebihan, karena ada lebih banyak hal untuk TDD, tetapi intinya adalah bahwa Anda tidak membuat yang terbaik pengalaman pengguna mungkin jika Anda berfokus pada fitur-fitur baru dan menarik dan menjaga integritas pada saat yang sama. Anda mendapatkannya setengah jalan dalam kedua kasus. Maksud saya, bagaimana Anda bisa tahu persis bagaimana banyak toilet dan di mana Anda harus tempat untuk 150000 orang? Saya jarang melihat stadion runtuh dalam hidup saya sendiri, tetapi saya harus mengantri selama setengah waktu dalam banyak kesempatan. Yang mengatakan bahwa masalah toilet bisa dibilang lebih kompleks dan jika para insinyur dapat menghabiskan lebih sedikit waktu untuk keselamatan, mereka akhirnya mungkin dapat menyelesaikan masalah toilet.

Poin kedua Anda tidak relevan, karena kami sudah sepakat bahwa absolut adalah saha bodoh dan karena Hank Moody mengatakan mereka tidak ada (tapi saya sepertinya tidak dapat menemukan referensi untuk itu).

2
Filip Dupanović

Saya tidak suka Anda mengatakan 'tes, daripada pengguna, menetapkan persyaratan'. Saya pikir Anda hanya mempertimbangkan pengujian unit di TDD, sedangkan itu juga mencakup pengujian integrasi.

Selain menguji perpustakaan yang menjadi dasar perangkat lunak, tulis tes yang mencakup interaksi pengguna Anda dengan perangkat lunak/situs web/apa pun. Ini datang langsung dari pengguna, dan perpustakaan seperti mentimun (http://cukes.info) bahkan dapat membiarkan pengguna Anda menulis tes sendiri, dalam bahasa alami.

TDD juga mendorong fleksibilitas dalam kode - jika Anda menghabiskan selamanya merancang arsitektur sesuatu, itu akan sangat sulit untuk membuat perubahan itu nanti jika perlu. Mulailah dengan menulis beberapa tes, lalu tulis kode kecil yang lulus tes tersebut. Tambahkan lebih banyak tes, tambahkan lebih banyak kode. Jika Anda perlu mengubah kode secara radikal, pengujian Anda masih berlaku.

Dan tidak seperti jembatan dan mobil, satu perangkat lunak dapat mengalami perubahan besar selama masa pakainya, dan melakukan refactoring yang rumit tanpa tes tertulis pertama hanya meminta untuk masalah.

2
sevenseacat

Jika Anda menerima bahwa semakin cepat bug ditemukan, semakin sedikit biaya untuk memperbaikinya, maka itu saja membuat TDD berharga.

1
SnoopDougieDoug

TDD dalam rekayasa perangkat lunak adalah praktik yang baik, dengan cara yang sama seperti penanganan kesalahan dalam aplikasi adalah praktik yang baik serta pencatatan dan diagnostik (meskipun itu merupakan bagian dari penanganan kesalahan).

TDD tidak dapat digunakan sebagai alat untuk mengurangi pengembangan perangkat lunak menjadi kode coba-coba & kesalahan. Tapi tetap saja, sebagian besar programmer menatap log runtime, menonton pengecualian dalam debugger atau menggunakan tanda-tanda kegagalan/kesuksesan lainnya selama fase pengembangan mereka yang terdiri dari pengkodean/kompilasi/menjalankan aplikasi - sepanjang hari.

TDD hanyalah cara untuk memformalkan dan mengotomatiskan langkah-langkah tersebut untuk menjadikan Anda sebagai pengembang lebih produktif.

1) Anda tidak dapat membandingkan rekayasa perangkat lunak dengan konstruksi jembatan, fleksibilitas dalam konstruksi jembatan tidak jauh dari merancang program perangkat lunak. Membangun jembatan seperti menulis program yang sama berulang-ulang menjadi mesin yang hilang. Jembatan tidak dapat diduplikasi dan digunakan kembali sebagaimana perangkat lunak dapat. Setiap jembatan itu unik dan harus dibuat. Hal yang sama berlaku untuk mobil dan desain lainnya.

Hal tersulit dalam rekayasa perangkat lunak adalah mereproduksi kesalahan, ketika jembatan gagal biasanya sangat mudah untuk menentukan apa yang salah, dan secara teori mudah untuk mereproduksi kegagalan. Ketika sebuah program komputer gagal, itu bisa menjadi rangkaian peristiwa yang kompleks yang membawa sistem ke keadaan salah dan bisa sangat sulit untuk menentukan di mana kesalahannya. TDD dan uji unit membuatnya lebih mudah untuk menguji ketahanan komponen perangkat lunak, perpustakaan dan algoritma.

2) Menggunakan unit test yang lemah dan test case yang dangkal yang tidak menekankan sistem untuk membangun rasa percaya diri yang salah adalah praktik yang buruk. Mengabaikan kualitas arsitektur suatu sistem dan hanya memenuhi tes tentu saja buruk. Tapi menipu di tempat konstruksi untuk gedung pencakar langit atau jembatan untuk menghemat bahan dan tidak mengikuti cetak biru sama buruknya dan itu terjadi setiap saat ...

1
Ernelli

Saya akan memberi Anda jawaban singkat. Biasanya TDD dipandang dengan cara yang salah sama seperti pengujian unit. Saya tidak pernah mengerti pengujian unit sampai baru-baru ini setelah menonton video pembicaraan teknologi yang bagus. Pada dasarnya TDD hanya menyatakan Anda ingin hal-hal berikut BEKERJA. Mereka HARUS dilaksanakan. Kemudian Anda mendesain sisa perangkat lunak seperti biasa.

Jenisnya seperti menulis menggunakan case untuk perpustakaan sebelum mendesain perpustakaan. Kecuali Anda dapat mengubah use case di perpustakaan dan Anda mungkin tidak untuk TDD (Saya menggunakan TDD untuk desain API). Anda juga didorong untuk menambahkan lebih banyak tes dan memikirkan input/penggunaan liar yang mungkin didapat dari tes ini. Saya merasa berguna saat menulis perpustakaan atau API di mana jika Anda mengubah sesuatu, Anda harus tahu Anda memecahkan sesuatu. Dalam sebagian besar perangkat lunak sehari-hari saya tidak repot karena mengapa saya perlu test case untuk pengguna menekan tombol atau jika saya ingin menerima daftar CSV atau daftar dengan satu entri per baris ... Itu tidak masalah saya mengizinkan untuk mengubahnya jadi saya seharusnya/tidak bisa menggunakan TDD.

0
user2528

Mengapa TDD berfungsi?

Tidak.

Klarifikasi: tes otomatis lebih baik daripada tidak ada tes. Namun saya pribadi berpikir bahwa sebagian besar unit test adalah pemborosan karena biasanya tautologis (yaitu mengatakan hal-hal yang jelas dari kode aktual yang diuji) dan tidak dapat dengan mudah dibuktikan bahwa mereka konsisten, tidak berlebihan dan mencakup semua kasus perbatasan (di mana kesalahan biasanya terjadi ).

Dan yang paling penting: Desain perangkat lunak yang baik tidak secara ajaib keluar dari tes seperti yang diiklankan oleh banyak penginjil tangkas/TDD. Semua orang yang mengklaim sebaliknya tolong berikan tautan ke penelitian ilmiah yang ditinjau oleh rekan sejawat yang membuktikan hal ini, atau setidaknya rujukan ke beberapa proyek sumber terbuka di mana manfaat TDD dapat dipelajari secara potensial dengan kode perubahan sejarahnya.

0
KolA

TDD sebenarnya bukan tentang pengujian. Dan tentu saja itu bukan pengganti untuk pengujian yang baik. Apa yang ia berikan kepada Anda adalah desain yang dipikirkan dengan baik, mudah dikonsumsi konsumen, dan mudah dipelihara serta diperbaiki lagi nanti. Hal-hal itu pada gilirannya menyebabkan lebih sedikit bug dan desain perangkat lunak yang lebih baik dan lebih mudah beradaptasi. TDD juga membantu Anda memikirkan dan mendokumentasikan asumsi Anda, seringkali menemukan bahwa beberapa di antaranya salah. Anda menemukan ini sangat awal dalam proses.

Dan sebagai manfaat sisi yang baik, Anda memiliki serangkaian besar tes yang dapat Anda jalankan untuk memastikan bahwa refactoring tidak mengubah perilaku (input dan output) dari perangkat lunak Anda.

0
Marcie

Perangkat lunak adalah organik, ketika rekayasa struktural beton.

Ketika Anda membangun jembatan Anda, itu akan tetap menjadi jembatan dan kecil kemungkinannya akan berkembang menjadi sesuatu yang lain dalam waktu singkat. Perbaikan akan dilakukan selama berbulan-bulan dan bertahun-tahun, tetapi tidak berjam-jam seperti dalam perangkat lunak.

Saat Anda menguji secara terpisah, biasanya ada dua jenis kerangka kerja yang dapat Anda gunakan. Kerangka kerja terbatas dan tidak dibatasi. Kerangka kerja yang tidak dibatasi (dalam .NET) memungkinkan Anda untuk menguji dan mengganti semuanya, terlepas dari pengubah akses. Yaitu. Anda dapat mematikan dan mengejek komponen pribadi dan yang dilindungi.

Sebagian besar proyek yang saya lihat menggunakan kerangka kerja terbatas (RhinoMocks, NSubstitute, Moq). Ketika Anda menguji dengan kerangka kerja ini, Anda harus merancang aplikasi Anda sedemikian rupa sehingga Anda bisa menyuntikkan dan mengganti dependensi saat runtime. Ini menyiratkan bahwa Anda harus memiliki desain yang digabungkan secara longgar. Desain yang digabungkan secara longgar (bila dilakukan dengan benar) menyiratkan pemisahan kekhawatiran yang lebih baik, yang merupakan hal yang baik.

Untuk meringkas, saya percaya bahwa berpikir di balik ini, adalah bahwa jika desain Anda dapat diuji, maka itu digabungkan secara longgar dan memiliki pemisahan keprihatinan yang baik.

Di samping catatan, saya telah melihat aplikasi yang benar-benar dapat diuji, tetapi ditulis dengan buruk dari perspektif desain berorientasi objek.

0
CodeART