Bisakah metodologi TDD diterapkan top-down?

13

Saya tidak jelas bagaimana TDD, metodologi, menangani kasus berikut. Misalkan saya ingin mengimplementasikan algoritma mergesort, dengan Python. Saya mulai dengan menulis

assert mergesort([]) === []

dan tes gagal dengan

NameError: nama 'mergesort' tidak didefinisikan

Saya kemudian menambahkan

def mergesort(a):
    return []

dan tes saya lolos. Selanjutnya saya tambahkan

assert mergesort[5] == 5

dan pengujian saya gagal dengan

AssertionError

yang saya buat lulus

def mergesort(a):
    if not a:
        return []
    else:
        return a

Selanjutnya, saya tambahkan

assert mergesort([10, 30, 20]) == [10, 20, 30]

dan saya sekarang harus mencoba untuk lulus ini. Saya "tahu" algoritma mergesort jadi saya menulis:

def mergesort(a):
    if not a:
        return []
    else:
        left, right = a[:len(a)//2], a[len(a)//2:]
        return merge(mergesort(left)), mergesort(right))

Dan ini gagal dengan

NameError: name 'merge' tidak didefinisikan

Sekarang inilah pertanyaannya. Bagaimana saya bisa lari dan mulai menerapkan mergemenggunakan TDD? Sepertinya saya tidak bisa karena saya mengalami "gagal" gagal, ujian gagal untuk mergesort, yang tidak akan berlalu sampai mergeselesai! Jika tes ini berlangsung, saya tidak akan pernah bisa melakukan TDD karena saya tidak akan menjadi "hijau" selama pembuatan iterasi TDD saya merge.

Sepertinya saya terjebak dengan tiga skenario buruk berikut, dan ingin tahu (1) yang mana yang disukai komunitas TDD, atau (2) apakah ada pendekatan lain yang saya lewatkan? Saya telah menyaksikan beberapa penelusuran TDD Paman Bob dan tidak ingat melihat kasus seperti ini sebelumnya!

Berikut adalah 3 kasus:

  1. Terapkan penggabungan dalam direktori yang berbeda dengan rangkaian uji yang berbeda.
  2. Jangan khawatir menjadi hijau saat mengembangkan fungsi helper, hanya melacak secara manual tes mana yang benar - benar ingin Anda lewati.
  3. Mengomentari (GASP!) Atau menghapus saluran dalam mergesortpanggilan itu merge; lalu setelah mulai mergebekerja, masukkan kembali.

Ini semua tampak konyol bagi saya (atau saya melihat ini salah?). Adakah yang tahu pendekatan yang disukai?

Ray Toal
sumber
2
Bagian dari tujuan TDD adalah membantu Anda membuat desain perangkat lunak. Bagian dari proses desain itu adalah menemukan apa yang diperlukan untuk menghasilkan hasil yang diinginkan. Dalam kasus mergesort, karena sudah merupakan algoritma yang terdefinisi dengan sangat baik, proses penemuan ini tidak diperlukan, dan kemudian menjadi masalah pemetaan apa yang sudah Anda ketahui sebagai desain untuk serangkaian tes unit. Agaknya, tes tingkat atas Anda menegaskan bahwa metode Anda dalam pengujian menerima koleksi yang tidak disortir dan mengembalikan koleksi yang disortir ...
Robert Harvey
1
... Uji unit selanjutnya secara bertahap akan menggali lebih dalam ke dalam mekanika sebenarnya dari a mergesort. Jika Anda mencari cara "benar" untuk melakukan ini, tidak ada satu, selain menjadi akurat tentang pemetaan mergesortalgoritma Anda ke serangkaian tes unit; yaitu mereka harus mencerminkan apa yang mergesortsebenarnya dilakukan.
Robert Harvey
4
Desain tidak tumbuh sendiri dari unit test saja; jika Anda mengharapkan mergesortdesain muncul secara alami dari red-green-refactor, itu tidak akan terjadi kecuali jika Anda memandu proses berdasarkan pengetahuan Anda yang ada mergesort.
Robert Harvey
1
Dalam TDD mergeharus diciptakan hanya pada tahap "refactoring". Jika Anda melihat mergemetode itu dapat diperkenalkan untuk lulus dari tes mergesortAnda, pertama-tama buat tes Anda berlalu tanpa mergemetode. Kemudian refactor implementasi Anda dengan memperkenalkan mergemetode.
Fabio

Jawaban:

13

Berikut adalah beberapa cara alternatif untuk melihat opsi Anda. Tapi pertama-tama, aturan TDD, dari Paman Bob dengan penekanan oleh saya:

  1. Anda tidak diperbolehkan untuk menulis kode produksi apa pun kecuali untuk membuat lulus uji unit yang gagal.
  2. Anda tidak diperbolehkan menulis lebih dari satu unit tes daripada yang cukup untuk gagal; dan kegagalan kompilasi adalah kegagalan.
  3. Anda tidak diperbolehkan menulis kode produksi lebih dari cukup untuk lulus satu unit test gagal.

Jadi, satu cara untuk membaca aturan nomor 3 adalah bahwa Anda memerlukan mergefungsi untuk lulus tes, sehingga Anda dapat mengimplementasikannya - tetapi hanya dalam bentuk yang paling dasar.

Atau, secara bergantian, Anda mulai dengan menulis operasi gabungan inline, dan kemudian refactor menjadi fungsi setelah mendapatkan tes untuk bekerja.

Penafsiran lain adalah bahwa Anda menulis mergesort, Anda tahu bahwa Anda akan memerlukan mergeoperasi (yaitu, itu bukan YAGNI, yang merupakan apa yang berusaha dikurangi oleh aturan "cukup"). Oleh karena itu, Anda harus mulai dengan tes untuk penggabungan, dan baru kemudian melanjutkan ke tes untuk keseluruhan jenis.

kdgregory
sumber
Ini adalah pengamatan yang sangat bagus. Saya sudah memikirkan inline-and-factoring yang keluar sebelumnya, tetapi mergesecara mengejutkan berantakan, bijaksana-tepi-(dan juga berguna sebagai mandiri) ide untuk melakukannya sebagai fungsi terpisah lebih masuk akal. Namun, gaya melakukannya sejajar dalam bentuk dasarnya dan kemudian memperhitungkannya pada tahap topi biru tampaknya benar dan sangat sesuai dengan apa yang saya cari.
Ray Toal
@ RayToal - Saya benar-benar bersandar pada pendekatan pengujian sepenuhnya mergeoperasi sebelum melakukan semacam itu (serta pengujian terpisah partitionoperasi). Saya berpikir bahwa manfaat yang muncul dari desain muncul berasal dari bekerja secara perlahan menuju tujuan yang diketahui. Dalam kasus mergesort, saya tidak berpikir tujuannya adalah penyortiran secara umum (karena Anda akan berakhir dengan semacam gelembung). Anda tahu operasi dasar, jadi Anda bekerja menuju operasi itu; jenisnya sebagian besar adalah renungan.
kdgregory
1
Ada opsi keempat. Pass mergefungsi ke dalam mergesortdan mengejek perilakunya. Kemudian kembali dan lakukan mergetes terlebih dahulu. Delegasi luar biasa ™.
RubberDuck
@RubberDuck Mengolok-olok bagian integral dari domain inti dapat menyebabkan beberapa masalah, lebih khusus ketika Anda menjalankan program dan fungsi mengejek dan menggabungkan berbeda dalam detail paling sedikit. Pendekatan seperti itu harus dibiarkan untuk contoh di mana Anda bekerja dengan sumber daya eksternal seperti dari mana daftar untuk menyortir berasal.
cllamach