Apa kerugian dari penulisan kode sebelum menulis unit test?

33

Saya selalu melihat rekomendasi bahwa kita harus terlebih dahulu menulis unit test dan kemudian mulai menulis kode. Tetapi saya merasa bahwa sebaliknya akan jauh lebih nyaman (bagi saya) - tulis kode dan kemudian tes unit, karena saya merasa kita memiliki kejelasan lebih banyak setelah kita menulis kode yang sebenarnya. Jika saya menulis kode dan kemudian tes, saya mungkin harus mengubah kode saya sedikit untuk membuatnya dapat diuji, bahkan jika saya banyak berkonsentrasi pada pembuatan desain yang dapat diuji. Di sisi lain, jika saya menulis tes dan kemudian kode, tes akan berubah cukup sering ketika kode terbentuk.

Ketika saya melihat banyak rekomendasi untuk mulai menulis tes dan kemudian beralih ke pengkodean, apa kerugiannya jika saya melakukannya dengan cara lain - menulis kode dan kemudian tes unit?

k25
sumber
7
+1 untuk menanyakan mengapa praktik tertentu adalah "praktik terbaik" sebelum merangkulnya
TaylorOtwell

Jawaban:

37

Merah adalah jawabannya. Merah adalah apa yang Anda dapatkan dari siklus merah-hijau-refactor TDD yang tidak bisa Anda dapatkan, tes-terakhir. Pertama, tulis tes yang gagal. Tonton itu gagal. Itu merahmu, dan itu penting. Dikatakan: Saya memiliki persyaratan ini dan saya tahu kode saya tidak memuaskannya. Jadi, ketika Anda pergi ke langkah 2 (hijau), Anda tahu, dengan kepastian yang sama, bahwa kode Anda sekarang memenuhi persyaratan itu. Anda tahu bahwa Anda telah mengubah basis kode Anda sedemikian rupa untuk memenuhi persyaratan.

Persyaratan (tes) dikembangkan setelah kode, berdasarkan kode, menghilangkan Anda dari kepastian semacam itu, keyakinan itu.

Carl Manaster
sumber
+1 - poin dan poin bagus diambil! Terima kasih atas pendapat anda!
k25
7
Tes! = Persyaratan. Baik tes dan kode harus berasal dari persyaratan.
Bart van Ingen Schenau
2
@ Bart van Ingen Schenau: Kekuatan TDD justru menguji persyaratan ADA. Selain itu, mereka adalah persyaratan yang dapat dieksekusi.
mouviciel
1
@Bart: Tes unit sering kali terlalu rinci untuk persyaratan pelanggan (tingkat tinggi), tetapi idenya pasti berlaku, terutama jika kita juga mempertimbangkan tes tingkat yang lebih tinggi seperti tes penerimaan otomatis yang, setelah ditulis, harus menjadi persyaratan yang pasti. Itulah esensi dari "pengujian penerimaan tangkas".
Martin Wickman
3
TDD bukan tentang pengujian, ini tentang spesifikasi. Pengujian yang dibangun dalam pendekatan TDD adalah sarana komunikasi antara pengembang dan pelanggan untuk menyetujui produk apa yang harus dibuat.
mouviciel
18

Jika Anda menulis kode, dan kemudian tes, terlalu mudah untuk jatuh ke dalam jebakan menulis tes sehingga kode lolos, daripada menulis tes untuk memastikan kode memenuhi spesifikasi.

Yang mengatakan, itu jelas bukan satu-satunya cara untuk melakukan sesuatu, dan tidak ada cara "terbaik" untuk mengembangkan perangkat lunak. Jika Anda menaruh banyak pekerjaan dimuka dalam mengembangkan kasus-kasus pengujian, Anda tidak tahu apakah arsitektur yang Anda ajukan memiliki kelemahan sampai beberapa waktu kemudian - sementara jika Anda mengembangkan kode terlebih dahulu, Anda akan mengalami lebih cepat dan dapat mendesain ulang dengan lebih sedikit tenggelam upaya.

Segera.
sumber
Ya, Anda benar tentang poin pertama, tetapi saya selalu memastikan saya tidak melakukan itu. Jika tes gagal, saya selalu pergi ke kode dan memastikan itu benar dan kemudian melihat apakah pengujian saya benar, dan kemudian memodifikasi mana yang salah. Terima kasih atas pendapat Anda, saya akan mengingat ini .. +1 dari saya untuk poin 1 dan poin terakhir ...
k25
2
Tetapi bagaimana jika tes itu lolos? Tes mungkin lulus karena tidak benar-benar menjalankan kode minat; itu tidak dapat benar-benar terjadi di bawah TDD, karena tes seharusnya gagal pada awalnya, dan tidak - jika tidak, Anda tidak melanjutkan ke langkah 2 sampai Anda memperbaikinya. Jadi ada mode kegagalan dalam pengujian terakhir yang tidak ada dalam pengujian terlebih dahulu.
Carl Manaster
@Carl Manaster - Ya, Anda memiliki poin yang valid. Setelah saya menulis kode, saya benar-benar menyadari persyaratannya sehingga case test unit saya benar (idealnya). Jika test case saya lolos, saya akan mengatakan kode itu benar, jika tes gagal, saya akan mengikuti apa yang saya katakan. Tapi, saya 100% setuju bahwa Anda memiliki poin yang valid di sana.
k25
@ k25: Intinya adalah jika test case Anda lulus, Anda masih tidak tahu apakah kodenya benar atau tidak. Kasus tes bisa salah.
Anon.
@Segera. - ya Anda benar, saya akan mempertimbangkan kasus ini juga.
k25
12

Sebenarnya, orang-orang yang terpaku pada TDD adalah tentang pengujian, meskipun mereka melupakan dua huruf lainnya dalam akronim. Sesuatu yang dapat dibaca di sini: TDD tanpa T atau TDD bukan tentang Pengujian .

Masalahnya adalah saya telah belajar banyak hal lain yang erat kaitannya dengan TDD. Tidak masalah jika Anda melakukan tes terlebih dahulu: Yang penting adalah memikirkan desain perangkat lunak .

Agar bahkan dapat menulis unit test "dengan cara yang benar", yaitu sehingga mereka terisolasi, cepat dan otomatis, semoga Anda akan memperhatikan bahwa diperlukan pemikiran ulang tentang bagaimana mengatur kode Anda sedemikian rupa sehingga kode Anda menjadi lebih mudah untuk menguji.

Secara pribadi saya belajar sendiri prinsip - prinsip PADAT tanpa mengetahui ada yang namanya tertulis. Ini karena tes unit menulis memaksa saya untuk menulis ulang kelas sehingga mereka tidak akan terlalu rumit untuk diuji. Itu mengarah pada hal-hal seperti:

  • Saya harus memindahkan fungsionalitas, yang tidak masuk akal atau tinggal di metode pribadi, ke kelas terpisah sehingga saya bisa mengujinya secara terpisah. (Prinsip Tanggung Jawab Tunggal).
  • Saya harus menghindari struktur warisan besar dan memperluas implementasi dengan komposisi sebagai gantinya (menonjol dalam prinsip Open-Closed).
  • Saya harus pandai tentang pewarisan, saya menggunakan kelas abstrak setiap kali saya melihat kode umum yang dapat dibagikan dan menggunakan metode rintisan (Prinsip Substitusi Liskov).
  • Saya harus menulis antarmuka dan kelas abstrak sehingga saya bisa menguji kelas dalam pemisahan. Yang secara tidak sengaja menuntun Anda untuk menulis benda tiruan. (Prinsip Segregasi Antarmuka)
  • Karena saya menulis banyak antarmuka dan kelas abstrak, saya mulai mendeklarasikan variabel dan parameter untuk menggunakan tipe umum (Prinsip inversi ketergantungan).

Meskipun saya tidak melakukan tes-pertama sepanjang waktu, saya memang mengikuti prinsip-prinsip dan praktik OO yang baik yang mulai Anda ikuti, hanya untuk membuat pengujian sedikit lebih mudah. Sekarang saya tidak menulis kode untuk kepentingannya sendiri. Saya menulis kode sehingga dapat dengan mudah diuji atau yang lebih penting; mudah dirawat .

Spoike
sumber
1
+1 untuk SOLID secara alami terjadi pada Anda, ketika Anda berpikir tentang desain perangkat lunak.
ocodo
+1 (sebenarnya saya ingin memberi +10 tetapi saya tidak bisa). Pikiran saya tepat - daftar poin Anda sangat bagus. Itulah salah satu alasan saya menanyakan pertanyaan ini. Saya merasa kelas menjadi lebih ketika saya mulai menulis unit test setelah saya menulis kode. Tapi saya ingin melihat kelebihan / kekurangan dari kedua belah pihak, terima kasih atas pendapat Anda!
k25
10

Semua jawaban lainnya baik, tetapi ada satu hal yang tidak disinggung. Jika Anda menulis tes terlebih dahulu, itu memastikan bahwa tes ditulis. Sangat menggoda, setelah Anda menulis kode kerja, untuk melewati tes dan verifikasi saja melalui UI. Jika Anda memiliki disiplin untuk selalu memiliki tes gagal sebelum Anda menulis kode, Anda dapat menghindari jebakan ini.

RasionalGeek
sumber
4

Jika Anda menulis tes Anda terlebih dahulu, itu memberi Anda kesempatan lain untuk memikirkan desain Anda, sebelum desain itu "dilemparkan ke batu."

Misalnya, Anda mungkin berpikir bahwa Anda memerlukan metode yang mengambil serangkaian parameter tertentu. Dan jika Anda menulis kode terlebih dahulu, Anda akan menulisnya seperti itu dan membuat tes sesuai dengan parameter yang ditentukan. Tetapi jika Anda menulis tes pertama, Anda mungkin berpikir "tunggu sebentar, saya tidak ingin menggunakan parameter ini dalam kode arus utama, jadi mungkin saya harus mengubah API."

Segera
sumber
+1 untuk poin pertama. Tetapi, tidak sampai ke tingkat parameter, bagaimana jika desain itu didiskusikan dengan orang lain dan diterima?
k25
@ k25 - jika ada sesuatu yang sulit digunakan seperti yang dirancang, itu perlu lebih banyak pemikiran. Terkadang - sangat jarang - itu hanya tugas yang sulit. Tetapi lebih sering, ini dapat direduksi menjadi tugas yang lebih sederhana. Saya tidak memiliki tautan, tetapi Gosling atau Goetz melakukan wawancara tentang desain API beberapa tahun yang lalu ... layak untuk Googling.
Anon
tentu, terima kasih untuk petunjuknya, saya pasti akan melihat mereka ...
k25
2

Ketika saya melihat banyak rekomendasi untuk mulai menulis tes dan kemudian beralih ke pengkodean,

Ada alasan bagus untuk ini.

Jika Anda mengatakan "lakukan apa yang terasa benar", orang melakukan hal yang paling bodoh dan paling gila.

Jika Anda mengatakan "tulis tes terlebih dahulu", orang setidaknya mungkin mencoba melakukan hal yang benar.

apa kerugiannya jika saya melakukannya dengan cara lain - tulis kode dan kemudian tes unit?

Biasanya, tes yang buruk dan desain yang harus dikerjakan ulang untuk dapat diuji.

Namun, itu hanya "biasanya". Beberapa orang mengembangkan desain dan tes secara paralel. Beberapa orang menempatkan kode yang dapat diuji pada tempatnya dan menulis tes tanpa mengerjakan ulang.

Aturan "Test First" secara khusus ada untuk mengajar dan mengajar orang-orang yang tidak memiliki petunjuk sama sekali.

Dengan cara yang sama, kita diberitahu untuk selalu melihat "dua arah" sebelum menyeberang jalan. Namun, sebenarnya kita tidak melakukannya. Dan itu tidak masalah. Saya tinggal di negara drive kanan dan saya hanya perlu melihat ke kiri ketika mulai menyeberang.

Ketika saya mengunjungi negara drive sebelah kiri, melihat ke kiri hanya bisa membuat saya terbunuh.

Aturan dinyatakan sangat kuat karena suatu alasan.

Apa yang Anda lakukan adalah masalah Anda sendiri.

S.Lott
sumber
2

Inti dari penulisan tes ini adalah membuat Anda memikirkannya

  • cara menguji kodenya
  • antarmuka kode harus ada agar dapat diuji

jika Anda melakukan sesuatu yang sederhana, mungkin tidak masalah yang mana yang Anda tulis terlebih dahulu (meskipun baik untuk memupuk kebiasaan tes-pertama) karena tesnya akan sederhana dan antarmuka akan jelas

tetapi TDD meningkat menjadi tes penerimaan, bukan hanya pengujian unit, dan kemudian antarmuka menjadi non-sepele.

Steven A. Lowe
sumber
1

Pertama jika Anda tidak menulis tes Anda terlebih dahulu maka Anda tidak melakukan Test Driven Development (TDD). Manfaatnya banyak dan seringkali sulit dipercaya sampai Anda mempraktikkannya berkali-kali. Berikut adalah manfaat yang telah saya terima dengan melakukan TDD dibandingkan pengembangan tradisional:

  1. Jaring pengaman pengujian - memungkinkan Anda melakukan perubahan besar tanpa takut merusak sesuatu tanpa disadari
  2. Desain organik - desain yang saya gunakan biasanya berbeda dengan desain yang saya lakukan sejak awal dan selalu lebih baik
  3. Produktivitas - bekerja menuju tujuan kecil (lulus tes yang satu ini) dan menjadikannya (semua tes lulus) bekerja sangat baik untuk saya dan membuat saya tetap termotivasi. Tambahkan pasangan dan produktivitas saya mencapai tertinggi baru.

Buku: Beck, K. Pengembangan Didorong oleh Contoh

Contoh yang bagus: http://jamesshore.com/Blog/Lets-Play/

Mike Polen
sumber
+1 - poin bagus (terutama tanggal 1) dan terima kasih atas tautannya!
k25
0

Saat Anda menulis tes, bagaimana Anda tahu itu akan mendeteksi kondisi gagal? Jawabannya adalah "test the test". Cara Anda melakukannya adalah dengan menulis tes terlebih dahulu, melihatnya gagal, dan hanya melihatnya lulus ketika unit yang diuji telah berhasil dikodekan (siklus merah / hijau / refactor yang disebutkan dalam salah satu jawaban lain).

Menulis kode terlebih dahulu dan kemudian ujian membuka pertanyaan apakah tes akan menunjukkan kegagalan yang jujur.

Ingat bahwa tes Anda menyatakan spesifikasi. Jika Anda harus merevisi tes Anda sebagai kode "bentuk", itu menunjukkan bahwa spesifikasi Anda berubah. Itu mungkin atau mungkin bukan hal yang baik. Ini bisa berarti bahwa pemahaman Anda tentang masalah pada awalnya tidak benar. Di sisi lain, itu bisa berarti bahwa Anda menguji "bagaimana" unit melakukan tugasnya daripada apa yang seharusnya dicapai.

Zenilogix
sumber