Semua contoh yang saya baca dan lihat di video pelatihan memiliki contoh sederhana. Tapi apa yang saya tidak lihat jika bagaimana saya melakukan kode "nyata" setelah saya mendapatkan hijau. Apakah ini bagian "Refactor"?
Jika saya memiliki objek yang cukup kompleks dengan metode yang kompleks, dan saya menulis tes dan minimum untuk membuatnya lulus (setelah itu pertama kali gagal, Red). Kapan saya kembali dan menulis kode asli? Dan berapa banyak kode nyata yang harus saya tulis sebelum saya tes ulang? Saya menduga yang terakhir lebih intuisi.
Sunting: Terima kasih kepada semua yang menjawab. Semua jawaban Anda sangat membantu saya. Tampaknya ada berbagai ide tentang apa yang saya tanyakan atau bingung, dan mungkin ada, tetapi yang saya tanyakan adalah, katakan saya memiliki aplikasi untuk membangun sekolah.
Dalam desain saya, saya memiliki arsitektur yang ingin saya mulai dengan, Cerita Pengguna, dan sebagainya. Dari sini, saya mengambil Cerita Pengguna tersebut, dan saya membuat tes untuk menguji Kisah Pengguna. Pengguna mengatakan, Kami memiliki orang yang mendaftar ke sekolah dan membayar biaya pendaftaran. Jadi, saya memikirkan cara untuk membuatnya gagal. Dengan melakukan itu saya merancang Tes kelas untuk kelas X (mungkin Siswa), yang akan gagal. Saya kemudian membuat kelas "Siswa." Mungkin "Sekolah" saya tidak tahu.
Tapi, bagaimanapun, Desain TD memaksa saya untuk memikirkan cerita. Jika saya dapat membuat tes gagal, saya tahu mengapa itu gagal, tetapi ini mengandaikan saya bisa lulus. Ini tentang mendesain.
Saya menyamakan ini dengan berpikir tentang Rekursi. Rekursi bukanlah konsep yang sulit. Mungkin lebih sulit untuk benar-benar melacaknya di kepala Anda, tetapi pada kenyataannya, bagian tersulit adalah mengetahui, ketika rekursi "pecah," kapan harus berhenti (pendapat saya, tentu saja.) Jadi saya harus memikirkan apa yang berhenti Rekursi pertama. Ini hanya analogi yang tidak sempurna, dan mengasumsikan bahwa setiap iterasi rekursif adalah "pass." Sekali lagi, hanya sebuah opini.
Dalam implementasinya, sekolah lebih sulit dilihat. Buku besar numerik dan perbankan "mudah" dalam arti Anda dapat menggunakan aritmatika sederhana. Saya dapat melihat a + b dan mengembalikan 0, dll. Dalam hal sistem orang, saya harus berpikir lebih keras tentang bagaimana mengimplementasikannya . Saya memiliki konsep gagal, lulus, refactor (kebanyakan karena studi dan pertanyaan ini.)
Apa yang saya tidak tahu didasarkan pada kurangnya pengalaman, menurut pendapat saya. Saya tidak tahu bagaimana cara gagal mendaftar siswa baru. Saya tidak tahu bagaimana cara seseorang gagal mengetik nama belakang dan itu disimpan ke database. Saya tahu cara membuat +1 untuk matematika sederhana, tetapi dengan entitas seperti orang, saya tidak tahu apakah saya hanya menguji untuk melihat apakah saya mendapatkan kembali ID unik basis data atau sesuatu yang lain ketika seseorang memasukkan nama dalam sebuah database atau keduanya atau tidak.
Atau, mungkin ini menunjukkan saya masih bingung.
Jawaban:
Anda tidak "kembali" dan menulis "kode nyata". Itu semua kode nyata. Apa yang Anda lakukan adalah kembali dan menambahkan tes lain yang memaksa Anda untuk mengubah kode Anda untuk membuat lulus ujian baru.
Adapun berapa banyak kode yang Anda tulis sebelum diuji ulang? Tidak ada Anda menulis kode nol tanpa gagal tes yang memaksa Anda untuk menulis lebih banyak kode.
Perhatikan polanya?
Mari kita telusuri (contoh lain) sederhana dengan harapan bisa membantu.
Pei mudah.
Bukan apa yang Anda sebut kode nyata, bukan? Mari kita tambahkan tes yang memaksa perubahan.
Kita bisa melakukan sesuatu yang konyol
if n == 1
, tetapi kita akan beralih ke solusi yang waras.Keren. Ini akan berfungsi untuk semua nomor non-FizzBuzz. Apa masukan selanjutnya yang akan memaksa kode produksi untuk berubah?
Dan lagi. Tulis tes yang belum lulus.
Dan kami sekarang telah membahas semua kelipatan tiga (yang tidak juga kelipatan lima, kami akan mencatatnya dan kembali).
Kami belum menulis tes untuk "Buzz", jadi mari kita tulis itu.
Dan lagi, kita tahu ada kasus lain yang perlu kita tangani.
Dan sekarang kita bisa menangani semua kelipatan 5 yang tidak kelipatan 3.
Sampai saat ini, kami telah mengabaikan langkah refactoring, tetapi saya melihat beberapa duplikasi. Mari kita bersihkan sekarang.
Keren. Sekarang kami telah menghapus duplikasi dan membuat fungsi yang bernama baik. Apa tes selanjutnya yang dapat kita tulis yang akan memaksa kita untuk mengubah kode? Yah, kita telah menghindari kasus di mana angka itu dapat dibagi oleh 3 dan 5. Mari kita tulis sekarang.
Tes lulus, tetapi kami memiliki lebih banyak duplikasi. Kami memiliki opsi, tetapi saya akan menerapkan "Ekstrak Variabel Lokal" beberapa kali sehingga kami melakukan refactoring alih-alih menulis ulang.
Dan kami telah membahas setiap input yang masuk akal, tetapi bagaimana dengan input yang tidak masuk akal ? Apa yang terjadi jika kita melewati 0 atau negatif? Tulis kasus uji itu.
Apakah ini mulai terlihat seperti "kode nyata"? Lebih penting lagi, pada titik mana ia berhenti menjadi "kode tidak nyata" dan transisi menjadi "nyata"? Itu sesuatu untuk direnungkan ...
Jadi, saya bisa melakukan ini hanya dengan mencari tes yang saya tahu tidak akan lulus pada setiap langkah, tetapi saya sudah banyak berlatih. Ketika saya sedang bekerja, banyak hal tidak sesederhana ini dan saya mungkin tidak selalu tahu tes apa yang akan memaksa perubahan. Terkadang saya akan menulis tes dan terkejut melihatnya sudah lulus! Saya sangat menyarankan agar Anda terbiasa membuat "Daftar Tes" sebelum memulai. Daftar tes ini harus berisi semua input "menarik" yang dapat Anda pikirkan. Anda mungkin tidak menggunakan semuanya dan Anda kemungkinan akan menambahkan kasus saat bepergian, tetapi daftar ini berfungsi sebagai peta jalan. Daftar tes saya untuk FizzBuzz akan terlihat seperti ini.
sumber
Kode "asli" adalah kode yang Anda tulis untuk membuat test pass Anda. Sungguh . Sesederhana itu.
Ketika orang berbicara tentang menulis minimum untuk membuat tes hijau, itu hanya berarti bahwa kode asli Anda harus mengikuti prinsip YAGNI .
Gagasan langkah refactor hanya untuk membersihkan apa yang telah Anda tulis begitu Anda senang bahwa itu memenuhi persyaratan.
Selama tes yang Anda tulis benar-benar mencakup persyaratan produk Anda, begitu mereka lulus maka kode selesai. Pikirkan tentang hal ini, jika semua persyaratan bisnis Anda memiliki tes dan semua tes itu hijau, apa lagi yang harus ditulis? (Oke, dalam kehidupan nyata kita cenderung tidak memiliki cakupan tes lengkap, tetapi teorinya sehat.)
sumber
switch
dengan kasing untuk setiap tes unit yang akan lulus semua tes dan gagal untuk input lainnya.switch
" saya dimaksudkan sebagai ekstrem logis dari "menulis minimum untuk membuat tes hijau". Saya melihat pertanyaan OP sebagai: di mana dalam TDD adalah prinsip yang menghindari sebesar iniswitch
?Jawaban singkatnya adalah "kode asli" adalah kode yang membuat lulus ujian. Jika Anda dapat lulus tes dengan sesuatu selain kode nyata, tambahkan lebih banyak tes!
Saya setuju bahwa banyak tutorial tentang TDD sederhana. Itu bekerja melawan mereka. Tes yang terlalu sederhana untuk metode yang, misalnya, menghitung 3 + 8 benar-benar tidak punya pilihan selain juga menghitung 3 + 8 dan membandingkan hasilnya. Itu membuatnya tampak seperti Anda hanya akan menduplikasi kode di seluruh, dan pengujian itu sia-sia, rawan kesalahan pekerjaan tambahan.
Ketika Anda mahir dalam pengujian, itu akan menginformasikan bagaimana Anda menyusun aplikasi Anda, dan bagaimana Anda menulis kode Anda. Jika Anda mengalami masalah dengan tes yang masuk akal dan membantu, Anda mungkin harus memikirkan kembali desain Anda sedikit. Sistem yang dirancang dengan baik mudah untuk diuji - yang berarti tes masuk akal mudah dipikirkan, dan diimplementasikan.
Ketika Anda menulis tes Anda terlebih dahulu, perhatikan gagal, dan kemudian tulis kode yang membuatnya lulus, itu adalah disiplin untuk memastikan bahwa semua kode Anda memiliki tes yang sesuai. Saya tidak dengan patuh mengikuti aturan itu ketika saya sedang coding; sering saya menulis tes setelah fakta. Tetapi melakukan tes terlebih dahulu membantu membuat Anda jujur. Dengan beberapa pengalaman, Anda akan mulai memperhatikan ketika Anda mengkodekan diri sendiri ke sudut, bahkan ketika Anda tidak menulis tes terlebih dahulu.
sumber
assertEqual(plus(3,8), 11)
, bukanassertEqual(plus(3,8), my_test_implementation_of_addition(3,8))
. Untuk kasus yang lebih kompleks, Anda selalu mencari cara untuk membuktikan hasil yang benar, selain secara dinamis menghitung hasil yang benar dalam tes dan memeriksa kesetaraan.plus(3,8)
telah mengembalikan hasil yang benar dengan mengurangi 3 dari itu, mengurangi 8 dari itu, dan memeriksa hasilnya terhadap 0. Ini sangat jelas samaassertEqual(plus(3,8), 3+8)
dengan menjadi Agak absurd, tetapi jika kode yang diuji membangun sesuatu yang lebih rumit dari sekedar integer, maka mengambil hasilnya dan memeriksa setiap bagian untuk kebenaran seringkali merupakan pendekatan yang tepat. Atau, sesuatu sepertifor (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
plus()
dapat menambahkan 10 untuk hal-hal. Kami masih mengandalkan nilai loop awal yang diverifikasi programmer, tentu saja.Terkadang beberapa contoh tentang TDD bisa menyesatkan. Seperti yang ditunjukkan orang lain sebelumnya, kode yang Anda tulis untuk membuat tes lulus adalah kode asli.
Tetapi jangan berpikir bahwa kode yang sebenarnya tampak seperti sihir - itu salah. Anda membutuhkan pemahaman yang lebih baik tentang apa yang ingin Anda capai dan kemudian Anda harus memilih tes yang sesuai, mulai dari kasing termudah dan kasing sudut.
Misalnya, jika Anda perlu menulis lexer, Anda mulai dengan string kosong, kemudian dengan sekelompok spasi putih, lalu angka, lalu dengan angka yang dikelilingi oleh spasi putih, lalu angka yang salah, dll. Transformasi kecil ini akan mengarahkan Anda ke algoritme yang tepat, tetapi Anda tidak beralih dari kasing termudah ke kasing rumit yang dipilih dengan bodoh untuk menyelesaikan kode sebenarnya.
Bob Martin menjelaskannya dengan sempurna di sini .
sumber
Bagian refactor dibersihkan ketika Anda lelah dan ingin pulang.
Saat Anda akan menambahkan fitur, bagian refactor adalah apa yang Anda ubah sebelum tes berikutnya. Anda membuat ulang kode untuk memberi ruang bagi fitur baru. Anda melakukan ini ketika Anda tahu apa yang akan menjadi fitur baru itu. Tidak ketika Anda hanya membayangkannya.
Hal ini dapat yang sederhana seperti mengubah nama
GreetImpl
untukGreetWorld
sebelum Anda membuatGreetMom
kelas (setelah menambahkan test) untuk menambahkan fitur yang akan mencetak "Hi Mom".sumber
Tetapi kode sebenarnya akan muncul pada tahap refactor dari fase TDD. Yakni kode yang harus menjadi bagian dari rilis final.
Tes harus dijalankan setiap kali Anda membuat perubahan.
Moto siklus hidup TDD adalah: RED GREEN REFACTOR
MERAH : Tulis tesnya
HIJAU : Berusaha jujur untuk mendapatkan kode fungsional yang lulus tes secepat mungkin: kode duplikat, nama variabel yang diretas dengan urutan paling tinggi, dll.
REFACTOR : Bersihkan kode, beri nama variabel dengan benar. KERING kodenya.
sumber
The merah fase adalah di mana Anda menulis kode.
Pada fase refactoring , tujuan utamanya adalah menghapus kode.
Pada fase merah Anda melakukan apa saja untuk membuat tes lulus secepat mungkin dan dengan biaya berapa pun . Anda sama sekali mengabaikan apa yang pernah Anda dengar tentang praktik pengkodean yang baik atau pola desain yang sama. Membuat tes hijau adalah yang terpenting.
Pada fase refactoring Anda membersihkan kekacauan yang baru saja Anda buat. Sekarang pertama-tama Anda melihat apakah perubahan yang baru saja Anda buat adalah jenis yang paling atas dalam daftar Prioritas Transformasi dan jika ada duplikasi kode yang paling mungkin Anda hapus dengan menerapkan patter desain.
Akhirnya Anda meningkatkan keterbacaan dengan mengganti nama pengidentifikasi dan mengekstraksi angka ajaib dan / atau string literal ke konstanta.
Terima kasih telah menunjukkan ini.
Jadi itu adalah fase hijau di mana Anda menulis kode asli
Pada fase merah Anda menulis spesifikasi yang dapat dieksekusi ...
sumber
Anda menulis Kode Nyata sepanjang waktu.
Pada setiap langkah, Anda menulis kode untuk memenuhi persyaratan yang akan dipenuhi oleh kode Anda untuk penelepon berikutnya di kode Anda (yang mungkin Anda atau tidak ...).
Anda pikir Anda tidak sedang menulis kode yang berguna ( nyata ), karena suatu saat Anda mungkin akan menolaknya.
Apakah ini berarti bahwa meskipun Anda mengubah kode, kondisi kode satisified, dibiarkan tidak berubah. Dan pemeriksaan ( tes ) yang Anda laksanakan untuk memverifikasi kode Anda sudah ada untuk memverifikasi apakah modifikasi Anda mengubah apa pun. Jadi kode yang Anda tulis sepanjang waktu ada di sana, hanya dengan cara yang berbeda.
Alasan lain Anda mungkin berpikir bahwa itu bukan kode asli, adalah karena Anda sedang melakukan contoh di mana program akhir sudah dapat Anda lihat sebelumnya. Ini sangat bagus, karena ini menunjukkan Anda memiliki pengetahuan tentang domain tempat Anda pemrograman.
Tetapi seringkali programmer berada dalam domain yang baru , tidak diketahui oleh mereka. Mereka tidak tahu apa hasil akhirnya dan TDD adalah teknik untuk menulis program langkah demi langkah, mendokumentasikan pengetahuan kita tentang bagaimana sistem ini harus bekerja dan memverifikasi bahwa kode kita berfungsi seperti itu.
Ketika saya membaca The Book (*) di TDD, bagi saya fitur terpenting yang menonjol adalah: Daftar TODO. Ini menunjukkan kepada saya bahwa, TDD juga merupakan teknik untuk membantu pengembang fokus pada satu hal pada suatu waktu. Jadi ini juga merupakan jawaban untuk pertanyaan Anda tentang berapa banyak kode nyata untuk ditulis ? Saya akan mengatakan kode yang cukup untuk fokus pada 1 hal sekaligus.
(*) "Pengembangan Didorong oleh Uji: Dengan Contoh" oleh Kent Beck
sumber
Anda tidak menulis kode untuk membuat tes Anda gagal.
Anda menulis tes untuk menentukan seperti apa seharusnya sukses itu, yang semestinya semuanya gagal karena Anda belum menulis kode yang akan lulus.
Inti dari menulis tes yang awalnya gagal adalah melakukan dua hal:
Poin di balik red-green-refactor adalah bahwa menulis tes yang benar terlebih dahulu memberi Anda kepercayaan diri untuk mengetahui bahwa kode yang Anda tulis untuk lulus tes adalah benar, dan memungkinkan Anda untuk refactor dengan keyakinan bahwa tes Anda akan memberi tahu Anda segera setelah sesuatu rusak, sehingga Anda dapat segera kembali dan memperbaikinya.
Dalam pengalaman saya sendiri (C # /. NET), tes murni pertama adalah sedikit ideal yang tidak dapat dicapai, karena Anda tidak dapat mengkompilasi panggilan ke metode yang belum ada. Jadi "test first" benar-benar tentang pengkodean antarmuka dan implementasi stubbing terlebih dahulu, kemudian menulis tes terhadap bertopik (yang awalnya akan gagal) sampai bertopik dengan benar. Saya tidak pernah menulis "kode gagal", hanya membangun dari bertopik.
sumber
Saya pikir Anda mungkin bingung antara tes unit dan tes integrasi. Saya percaya mungkin ada juga tes penerimaan, tapi itu tergantung pada proses Anda.
Setelah Anda menguji semua "unit" kecil maka Anda menguji mereka semua dirakit, atau "terintegrasi." Itu biasanya seluruh program atau perpustakaan.
Dalam kode yang saya tulis, tes integrasi perpustakaan dengan berbagai program pengujian yang membaca data dan memasukkannya ke perpustakaan, lalu memeriksa hasilnya. Lalu saya melakukannya dengan utas. Lalu saya melakukannya dengan utas dan fork () di tengah. Kemudian saya menjalankannya dan mematikan -9 setelah 2 detik, kemudian saya memulainya dan memeriksa mode pemulihannya. Saya mengerjainya. Saya menyiksanya dengan berbagai cara.
Semua itu juga JUGA menguji, tetapi saya tidak memiliki tampilan yang cukup merah / hijau untuk hasilnya. Entah berhasil, atau saya menggali beberapa ribu baris kode kesalahan untuk mencari tahu mengapa.
Di situlah Anda menguji "kode nyata."
Dan saya hanya memikirkan hal ini, tetapi mungkin Anda tidak tahu kapan Anda seharusnya selesai menulis unit test. Anda selesai menulis unit test ketika tes Anda melakukan semua yang Anda tentukan harus dilakukan. Kadang-kadang Anda dapat kehilangan jejak itu di antara semua penanganan kesalahan dan tepi kasus, jadi Anda mungkin ingin membuat kelompok uji yang bagus dari tes jalur bahagia yang hanya langsung melalui spesifikasi.
sumber
Dalam menjawab judul pertanyaan: "Kapan Anda menulis kode" asli "dalam TDD?", Jawabannya adalah: 'hampir tidak pernah' atau 'sangat lambat'.
Anda terdengar seperti seorang siswa, jadi saya akan menjawab seolah-olah menasihati seorang siswa.
Anda akan belajar banyak pengkodean 'teori' dan 'teknik'. Mereka bagus untuk menghabiskan waktu pada kursus siswa yang terlalu mahal, tetapi sangat sedikit manfaatnya bagi Anda bahwa Anda tidak bisa membaca dalam sebuah buku setengah waktu.
Tugas seorang pembuat kode hanya untuk menghasilkan kode. Kode yang bekerja dengan sangat baik. Itulah sebabnya Anda, pembuat kode merencanakan kode dalam pikiran Anda, di atas kertas, dalam aplikasi yang sesuai, dll., Dan Anda berencana untuk mengatasi kemungkinan kelemahan / lubang di muka dengan berpikir secara logis dan lateral sebelum pengkodean.
Tetapi Anda perlu tahu cara memecah aplikasi Anda untuk dapat merancang kode yang layak. Misalnya, jika Anda tidak tahu tentang Little Bobby Table (xkcd 327), maka Anda mungkin tidak akan membersihkan input sebelum bekerja dengan database, sehingga Anda tidak akan dapat mengamankan data Anda di sekitar konsep itu.
TDD hanyalah alur kerja yang dirancang untuk meminimalkan bug dalam kode Anda dengan membuat tes tentang apa yang bisa salah sebelum Anda membuat kode aplikasi Anda karena pengkodean dapat menjadi sulit secara eksponensial semakin banyak kode yang Anda perkenalkan dan Anda lupa bug yang pernah Anda pikirkan. Setelah Anda berpikir bahwa Anda telah menyelesaikan aplikasi Anda, Anda menjalankan tes dan boom, semoga bug tertangkap dengan tes Anda.
TDD bukan - seperti yang diyakini sebagian orang - menulis tes, membuatnya lulus dengan kode minimal, menulis tes lain, mendapatkan lulus itu dengan kode minimal, dll. Sebaliknya, ini adalah cara membantu Anda membuat kode dengan percaya diri. Ideal kode refactoring berkelanjutan untuk membuatnya bekerja dengan tes adalah idiot, tetapi ini adalah konsep yang bagus di antara siswa karena membuat mereka merasa hebat ketika mereka menambahkan fitur baru dan mereka masih belajar cara membuat kode ...
Tolong jangan jatuh perangkap ini dan melihat peran Anda pengkodean untuk apa itu - pekerjaan seorang koder adalah hanya untuk menghasilkan kode. Kode yang bekerja dengan sangat baik. Sekarang, ingatlah Anda akan siap sebagai coder profesional, dan klien Anda tidak akan peduli jika Anda menulis 100.000 pernyataan, atau 0. Mereka hanya menginginkan kode yang berfungsi. Sebenarnya sangat bagus.
sumber