Bagaimana bayi Anda di TDD?

37

Hari ini kami melatih TDD dan menemukan titik kesalahpahaman berikut.

Tugasnya adalah untuk input "1,2" mengembalikan jumlah angka yang adalah 3. Apa yang saya tulis (dalam C #) adalah:

numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]); //task said we have two numbers and input is correct

Tapi cowok lain lebih suka melakukannya dengan cara lain. Pertama, untuk input "1,2" mereka menambahkan kode berikut:

if (input == "1,2")
   return 3;

Kemudian mereka memperkenalkan satu tes lagi untuk input "4,5" dan mengubah implementasi:

if (input == "1,2")
   return 3;
else if (input == "4,5")
   return 9;

Dan setelah itu mereka berkata "Oke, sekarang kita melihat polanya" dan menerapkan apa yang awalnya saya lakukan.

Saya pikir pendekatan kedua lebih cocok dengan definisi TDD tapi ... haruskah kita begitu ketat tentang hal itu? Bagi saya tidak apa-apa untuk melewati langkah-langkah bayi sepele dan menggabungkannya menjadi "langkah kembar" jika saya cukup yakin bahwa saya tidak akan melewatkan apa pun. Apakah aku salah?

Memperbarui. Saya telah membuat kesalahan dengan tidak menjelaskan bahwa itu bukan tes pertama. Sudah ada beberapa tes sehingga "return 3" sebenarnya bukan bagian kode yang paling sederhana untuk memenuhi persyaratan.

SiberianGuy
sumber
25
Begitu kecilnya sehingga rekan kerja saya membunyikan "Ooahhh dazso cuuuuuute"
Adel
6
@ Adel: Hampir tercekik saat sarapan, keyboard sekarang penuh atau ludah dan remah
Binary Worrier
2
@ Adel, untuk penutur asing, agak sulit bagi saya untuk memahami humor ini, tetapi saya kira rekan kerja Anda suka pertanyaan :)
SiberianGuy
8
@Idsa: Ini mentransposisi respons rekan kerja ketika diperlihatkan langkah pertama anak-anak "Ooahhh dazso cuuuuuute" = "Oh itu sangat lucu" (diucapkan dengan suara nyanyian-bukan-yang-sangat-sangat-lucu), dengan respons mereka ketika melihat Tes Unit ditulis oleh Adel, melihat langkah-langkah bayi Tes Unit mereka mengatakan "Oh itu sangat lucu". Reaksi terhadap langkah bayi nyata = reaksi terhadap tes unit "langkah bayi".
Binary Worrier
3
@Binaryworrier berharap saya bisa memberi Anda poin nyata untuk meluangkan waktu untuk menjelaskan
orangtua

Jawaban:

31

Tulis kode paling sederhana yang membuat tes lulus.

Tak satu pun dari Anda melakukan itu, sejauh yang saya bisa lihat.

Baby Step 1.

Uji: Untuk input "1,2" kembalikan jumlah angka yaitu 3

Buat tes gagal:

throw NotImplementedException();

Buat tes lulus:

return 3;

Baby Step 2.

Uji: Untuk input "1,2" kembalikan jumlah angka, yaitu 3

Uji: Untuk input "4,5" kembalikan jumlah angka, yaitu 9

Tes kedua gagal, jadi selesaikan:

numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]);

(Jauh lebih sederhana daripada daftar jika ... kembali)

Anda tentu saja dapat memperdebatkan Implementasi Jelas dalam kasus ini, tetapi jika Anda berbicara tentang melakukannya secara ketat dalam langkah-langkah kecil maka ini adalah langkah yang benar, IMO.

Argumennya adalah bahwa jika Anda tidak menulis tes kedua maka beberapa percikan terang dapat muncul kemudian dan "refactor" kode Anda untuk membaca:

return input.Length; # Still satisfies the first test

Dan, tanpa mengambil kedua langkah, Anda tidak pernah membuat tes kedua menjadi merah (artinya tes itu sendiri adalah dugaan).

pdr
sumber
Mengenai masukan Anda. Contoh panjang, dengan kesuksesan yang sama saya dapat membayangkan beberapa implementasi salah gila yang tidak akan tertangkap oleh kedua tes
SiberianGuy
@Idsa - Ya, tentu saja, dan semakin banyak tes yang Anda tulis, semakin gila implementasinya. input.Lengthtidak terlalu jauh, terutama jika input ke metode kebetulan merupakan pengukuran dari beberapa file di suatu tempat dan Anda secara tidak sengaja menyebut metode Anda Size().
pdr
6
+1. Sehubungan dengan cara belajar TDD, ini adalah cara yang benar. Setelah Anda mempelajarinya, Anda kadang-kadang dapat langsung menuju implementasi yang jelas, tetapi untuk merasakan TDD, ini jauh lebih baik.
Carl Manaster
1
Saya punya pertanyaan tentang "ujian" itu sendiri. Apakah Anda akan menulis tes baru untuk input "4,5", atau memodifikasi tes asli?
mxmissile
1
@ mxmissile: Saya akan menulis tes baru. Tidak memakan banyak waktu dan Anda berakhir dengan dua kali lebih banyak tes untuk melindungi Anda ketika Anda melakukan refactoring nanti.
pdr
50

Saya pikir cara kedua adalah pikiran mati rasa bodoh. Saya melihat nilai dalam membuat langkah-langkah yang cukup kecil, tetapi menulis zigot kecil itu (bahkan tidak bisa menyebutnya bayi) langkah-langkahnya sama saja dengan membuang-buang waktu. Apalagi jika masalah awal yang Anda selesaikan sudah sangat kecil.

Saya tahu ini pelatihan dan lebih tentang menunjukkan prinsip, tapi saya pikir contoh seperti itu melakukan TDD lebih buruk daripada baik. Jika Anda ingin menunjukkan nilai langkah bayi, setidaknya gunakan masalah di mana ada beberapa nilai di dalamnya.

Christophe Vanfleteren
sumber
+1 dan terima kasih telah membuat saya mencari dan mempelajari kata baru (asinine)
Marjan Venema
12
+1 karena menyebutnya bodoh, bodoh. TDD semuanya bagus dan seperti itu, tetapi seperti dengan teknik pemrograman modern hyped Anda harus berhati-hati untuk tidak tersesat di dalamnya.
stijn
2
"Terutama jika masalah awal yang kamu selesaikan sudah sangat kecil dengan sendirinya." - Jika inputnya adalah dua int untuk ditambahkan bersama, saya akan setuju dengan ini, tapi saya tidak yakin ketika itu "pisahkan string, parsing dua int dari hasil dan tambahkan mereka." Sebagian besar metode di dunia nyata tidak jauh lebih rumit dari itu. Bahkan, harus ada lebih banyak tes yang akan datang, untuk menutupi kasus tepi seperti menemukan dua koma, nilai-nilai non-integer, dll.
pdr
4
@ pdr: Saya setuju dengan Anda bahwa harus ada lebih banyak tes untuk menangani kasus tepi. Ketika Anda menulisnya dan perhatikan bahwa implementasi Anda perlu diubah untuk menanganinya, tentu saja lakukan itu. Saya kira saya hanya memiliki masalah dengan mengambil langkah-langkah zigot ke jalur bahagia pertama, "implementasi yang jelas", alih-alih hanya menuliskannya dan pergi dari sana. Saya tidak melihat nilai dalam menulis pernyataan if yang setiap serat di tubuh saya tahu hanya akan menghilang saat berikutnya.
Christophe Vanfleteren
1
@ChristopheVanfleteren: Ketika Beck menggambarkan implementasi yang jelas, ia menggunakan jumlah dari dua int sebagai contoh dan masih memberikan peringatan dramatis yang besar tentang bagaimana Anda akan mati rasa malu jika pasangan / peninjau Anda dapat memikirkan kode sederhana yang membuat tes lulus. Itu adalah kepastian mutlak jika Anda hanya menulis satu tes untuk skenario ini. Juga, saya bisa memikirkan setidaknya tiga cara "jelas" untuk menyelesaikan masalah ini: split & add, ganti koma dengan + dan evaluasi, atau gunakan regex. Maksud TDD adalah mengarahkan Anda ke pilihan yang benar.
pdr
19

Kent Beck membahas ini dalam bukunya, Test Driven Development: By Example.

Contoh Anda menunjukkan ' implementasi jelas ' - Anda ingin mengembalikan jumlah dua nilai input, dan ini adalah algoritma yang cukup mendasar untuk dicapai. Contoh tandingan Anda jatuh ke 'palsu sampai Anda berhasil' (meskipun kasus yang sangat sederhana).

Implementasi yang jelas dapat menjadi jauh lebih rumit dari ini - tetapi pada dasarnya itu muncul ketika spesifikasi untuk suatu metode cukup ketat - misalnya, kembalikan URL yang disandikan versi properti kelas - Anda tidak perlu membuang waktu dengan banyak pengkodean palsu.

Sebaliknya, rutinitas koneksi basis data akan memerlukan sedikit pemikiran dan pengujian sehingga tidak ada implementasi yang jelas (bahkan jika Anda mungkin telah menulis beberapa kali di proyek lain).

Dari buku:

Ketika saya menggunakan TDD dalam praktiknya, saya biasanya beralih di antara dua mode implementasi ini, Ketika semuanya berjalan lancar dan saya tahu apa yang harus diketik, saya memasukkan Obvious Implementation setelah Obvious Implementasi (menjalankan tes setiap kali untuk memastikan bahwa apa yang jelas bagi saya) masih jelas ke komputer). Segera setelah saya mendapatkan bilah merah yang tidak terduga, saya mencadangkan, beralih ke pemalsuan implementasi, dan refactor ke kode yang benar. Ketika kepercayaan diri saya kembali, saya kembali ke Obvious Implementations.

HorusKol
sumber
18

Saya melihat ini sebagai mengikuti surat hukum, tetapi tidak semangatnya.

Langkah bayi Anda harus:

Sesederhana mungkin, tetapi tidak sederhana.

Juga, kata kerja dalam metode ini adalah sum

if (input == "1,2")
   return 3;

bukan jumlah, ini adalah tes untuk input spesifik.

StuperUser
sumber
4

Bagi saya kelihatannya baik untuk menggabungkan beberapa langkah implementasi sepele menjadi satu yang sedikit kurang sepele - Saya juga selalu melakukannya. Saya tidak berpikir orang perlu menjadi religius tentang mengikuti TDD setiap kali surat itu.

OTOH ini hanya berlaku untuk langkah-langkah sepele seperti contoh di atas. Untuk sesuatu yang lebih kompleks, yang tidak dapat sepenuhnya saya ingat dalam pikiran saya sekaligus dan / atau di mana saya tidak yakin 110% tentang hasilnya, saya lebih suka melangkah satu langkah pada satu waktu.

Péter Török
sumber
1

Ketika pertama kali memulai jalan TDD ukuran langkah-langkah bisa menjadi masalah yang membingungkan, seperti yang digambarkan pertanyaan ini. Sebuah pertanyaan yang sering saya tanyakan pada diri saya ketika saya mulai menulis aplikasi yang digerakkan oleh tes adalah; Apakah tes yang saya tulis membantu mendorong pengembangan aplikasi saya? Ini mungkin tampak sepele dan tidak ada hubungannya dengan beberapa orang tetapi bertahan sebentar dengan saya.

Sekarang ketika saya mulai menulis aplikasi apa pun saya biasanya akan mulai dengan tes. Seberapa besar langkah yang sebagian besar dari tes ini berkaitan dengan pemahaman saya tentang apa yang saya coba lakukan. Jika saya pikir saya memiliki perilaku kelas di kepala saya maka langkahnya akan menjadi besar. Jika masalah yang saya coba selesaikan jauh lebih tidak jelas maka langkahnya mungkin saja saya tahu akan ada metode bernama X dan akan mengembalikan Y. Pada titik ini metode tersebut bahkan tidak akan memiliki parameter dan ada kemungkinan bahwa nama metode dan tipe pengembalian akan berubah. Dalam kedua kasus, tes mendorong perkembangan saya. Mereka memberi tahu saya hal-hal tentang aplikasi saya:

Apakah kelas ini yang ada di kepala saya benar-benar akan bekerja?

atau

Bagaimana aku bisa melakukan hal ini?

Intinya adalah saya bisa beralih antara langkah besar dan langkah kecil dalam sekejap mata. Misalnya, jika langkah besar tidak berhasil dan saya tidak bisa melihat jalan yang jelas, saya akan beralih ke langkah yang lebih kecil. Jika itu tidak berhasil saya akan beralih ke langkah yang lebih kecil. Lalu ada teknik lain seperti triangulasi jika saya benar-benar macet.

Jika seperti saya Anda adalah seorang pengembang dan bukan seorang tester maka tujuan menggunakan TDD bukan untuk menulis tes tetapi untuk menulis kode. Jangan terpaku pada penulisan banyak tes kecil jika tidak memberi Anda manfaat.

Saya harap Anda menikmati pelatihan Anda tongkat dengan TDD. IMHO jika lebih banyak orang yang terinfeksi tes maka dunia akan menjadi tempat yang lebih baik :)

lexx
sumber
1

Dalam sebuah primer tentang pengujian unit saya membaca pendekatan yang sama (langkah-langkah yang terlihat sangat, sangat kecil), dan sebagai jawaban untuk pertanyaan "seberapa kecil mereka seharusnya" sesuatu yang saya sukai, yang (diparafrasakan) seperti ini:

Ini tentang seberapa yakin Anda bahwa langkah-langkah itu berhasil. Anda dapat membuat langkah besar nyata jika Anda mau. Tapi, coba saja untuk beberapa waktu dan Anda akan menemukan banyak kepercayaan yang salah arah di tempat yang Anda anggap remeh. Jadi, tes ini membantu Anda membangun kepercayaan berbasis fakta.

Jadi, mungkin kolega Anda hanya pemalu :)

keppla
sumber
1

Bukankah seluruh poin bahwa implementasi metode ini tidak relevan, selama tes berhasil? Memperluas tes akan gagal lebih cepat dalam contoh kedua, tetapi dapat dibuat gagal dalam kedua kasus.

Dada
sumber
1
Ini tidak relevan jika Anda benar-benar tidak peduli membuang-buang waktu
SiberianGuy
1

Saya setuju dengan orang-orang yang mengatakan bahwa tidak ada implementasi yang paling sederhana.

Alasan metodologi ini sangat ketat adalah karena mengharuskan Anda untuk menulis sebanyak mungkin tes yang relevan. Mengembalikan nilai konstan untuk satu test case dan menyebutnya lulus tidak apa-apa karena memaksa Anda untuk kembali dan menentukan apa yang benar-benar Anda inginkan untuk mendapatkan apa pun selain omong kosong dari program Anda. Menggunakan kasus sepele seperti menembak diri sendiri dalam beberapa hal, tetapi prinsipnya adalah bahwa kesalahan masuk ke dalam celah dalam spesifikasi Anda ketika Anda mencoba untuk melakukan 'terlalu banyak' dan merender persyaratan untuk implementasi paling sederhana yang memungkinkan memastikan bahwa Tes harus ditulis untuk setiap aspek perilaku unik yang Anda inginkan.

Tom W
sumber
Saya telah menambahkan pembaruan tentang "mengembalikan nilai konstan"
SiberianGuy