Ini mungkin pertanyaan yang agak konyol karena saya pada upaya pertama saya di TDD. Saya menyukai rasa percaya diri yang dibawanya dan struktur kode saya yang umumnya lebih baik tetapi ketika saya mulai menerapkannya pada sesuatu yang lebih besar dari contoh mainan satu kelas, saya mengalami kesulitan.
Misalkan, Anda sedang menulis semacam perpustakaan. Anda tahu apa yang harus dilakukan, Anda tahu cara umum bagaimana seharusnya diterapkan (arsitektur bijaksana), tetapi Anda terus "menemukan" bahwa Anda perlu membuat perubahan pada API publik Anda saat Anda kode. Mungkin Anda perlu mengubah metode pribadi ini menjadi pola strategi (dan sekarang perlu lulus strategi yang dipermainkan dalam tes Anda), mungkin Anda salah menempatkan tanggung jawab di sana-sini dan membagi kelas yang ada.
Ketika Anda memperbaiki kode yang ada, TDD tampaknya sangat cocok, tetapi ketika Anda menulis semuanya dari awal, API yang Anda tulis tesnya agak "buram" kecuali jika Anda melakukan desain besar di depan. Apa yang Anda lakukan ketika Anda sudah memiliki 30 tes pada metode yang tandatangannya (dan untuk bagian itu, perilaku) berubah? Itu banyak tes yang harus diubah begitu dijumlahkan.
Jawaban:
Apa yang Anda sebut "desain besar di depan" saya sebut "perencanaan arsitektur kelas Anda yang masuk akal."
Anda tidak dapat menumbuhkan arsitektur dari tes unit. Bahkan Paman Bob mengatakan itu.
http://s3.amazonaws.com/hanselminutes/hanselminutes_0171.pdf , Halaman 4
Saya pikir akan lebih masuk akal untuk mendekati TDD dari perspektif memvalidasi desain struktural Anda. Bagaimana Anda tahu desainnya salah jika Anda tidak mengujinya? Dan bagaimana Anda memverifikasi bahwa perubahan Anda sudah benar tanpa juga mengubah tes asli?
Perangkat lunak "lunak" justru karena dapat berubah. Jika Anda merasa tidak nyaman dengan jumlah perubahan, terus mendapatkan pengalaman dalam desain arsitektur, dan jumlah perubahan yang perlu Anda buat agar arsitektur aplikasi Anda akan berkurang seiring waktu.
sumber
Jika Anda melakukan TDD. Anda tidak dapat mengubah tanda tangan dan perilaku tanpa didorong oleh tes. Jadi, 30 tes yang gagal dihapus dalam proses atau diubah / dire-refraktekan bersama dengan kode. Atau sekarang sudah usang, aman untuk dihapus.
Anda tidak dapat mengabaikan 30 kali merah dalam siklus merah-hijau-refactor Anda?
Tes Anda harus di refactored di samping kode produksi Anda. Jika Anda mampu, jalankan kembali semua tes setelah setiap perubahan.
Jangan takut untuk menghapus tes TDD. Beberapa tes akhirnya menguji blok bangunan untuk mencapai hasil yang diinginkan. Hasil yang diinginkan pada tingkat fungsional adalah yang terpenting. Pengujian di sekitar langkah-langkah perantara dalam algoritma yang Anda pilih / temukan mungkin atau mungkin tidak bernilai banyak ketika ada lebih dari satu cara untuk mencapai hasil atau Anda awalnya menemui jalan buntu.
Terkadang Anda dapat membuat beberapa tes integrasi yang layak, menyimpannya dan menghapus sisanya. Ini agak tergantung apakah Anda bekerja dalam ke luar atau dari atas ke bawah dan seberapa besar langkah yang Anda ambil.
sumber
Seperti yang dikatakan Robert Harvey, Anda mungkin mencoba menggunakan TDD untuk sesuatu yang harus ditangani oleh alat konseptual yang berbeda (yaitu: "desain" atau "pemodelan").
Cobalah untuk merancang (atau "model") sistem Anda dengan cara yang cukup abstrak ("umum", "tidak jelas"). Misalnya, jika Anda harus memodelkan mobil, cukup kelas mobil dengan beberapa metode dan bidang yang tidak jelas, seperti startEngine () dan kursi int. Yaitu: jelaskan apa yang ingin Anda paparkan kepada publik , bukan bagaimana Anda ingin mengimplementasikannya. Cobalah untuk mengekspos fungsionalitas dasar saja (baca, tulis, mulai, hentikan, dll) dan biarkan kode klien menguraikannya (persiapanMyScene (), killTheEnemy (), dll).
Tulis tes Anda dengan asumsi antarmuka publik sederhana ini.
Ubah perilaku internal kelas dan metode Anda kapan pun Anda membutuhkannya.
Jika dan ketika Anda perlu mengubah antarmuka publik dan ruang uji Anda, berhentilah dan pikirkan. Kemungkinan besar ini adalah tanda bahwa ada sesuatu yang salah di API Anda dan dalam desain / pemodelan Anda.
Sudah biasa mengubah API. Sebagian besar sistem pada versi 1.0 mereka secara eksplisit memperingatkan pemrogram / pengguna terhadap kemungkinan perubahan dalam API mereka. Meskipun demikian, aliran perubahan API yang terus-menerus dan tidak terkontrol merupakan tanda jelas dari desain yang buruk (atau sama sekali tidak ada).
BTW: Anda biasanya harus hanya memiliki beberapa tes per metode. Metode, menurut definisi, harus mengimplementasikan "tindakan" yang didefinisikan dengan jelas pada beberapa jenis data. Di dunia yang sempurna, ini harus menjadi tindakan tunggal yang sesuai dengan satu tes. Di dunia nyata bukan hal yang aneh (dan tidak salah) memiliki beberapa "versi" yang berbeda dari aksi yang sama dan beberapa tes yang sesuai. Yang pasti, Anda harus menghindari memiliki 30 tes pada metode yang sama. Ini adalah tanda yang jelas bahwa metode ini mencoba melakukan terlalu banyak (dan kode internalnya tumbuh di luar kendali).
sumber
Saya melihatnya dari perspektif pengguna. Misalnya, jika API Anda mengizinkan saya membuat objek Orang dengan nama dan usia, lebih baik ada konstruktor Orang (nama string, usia int) dan metode pengaksesor untuk nama dan usia. Sangat mudah untuk membuat test case untuk Orang baru dengan dan tanpa nama dan umur.
doug
sumber