Apa yang Anda lakukan saat menulis tes dan sampai pada titik di mana Anda perlu lulus ujian dan menyadari bahwa Anda memerlukan fungsionalitas tambahan yang harus dipisahkan ke dalam fungsinya sendiri? Fungsi baru itu perlu diuji juga, tetapi siklus TDD mengatakan untuk membuat tes gagal, membuatnya lulus kemudian refactor. Jika saya berada di langkah di mana saya mencoba untuk membuat tes lulus saya tidak seharusnya pergi dan memulai tes gagal lagi untuk menguji fungsionalitas baru yang perlu saya terapkan.
Sebagai contoh, saya menulis kelas titik yang memiliki fungsi WillCollideWith ( LineSegment ) :
public class Point {
// Point data and constructor ...
public bool CollidesWithLine(LineSegment lineSegment) {
Vector PointEndOfMovement = new Vector(Position.X + Velocity.X,
Position.Y + Velocity.Y);
LineSegment pointPath = new LineSegment(Position, PointEndOfMovement);
if (lineSegment.Intersects(pointPath)) return true;
return false;
}
}
Saya sedang menulis tes untuk CollidesWithLine ketika saya menyadari bahwa saya akan membutuhkan fungsi LineSegment.Intersects ( LineSegment ) . Tetapi, haruskah saya menghentikan apa yang saya lakukan pada siklus pengujian untuk membuat fungsi baru ini? Itu tampaknya melanggar prinsip "Merah, Hijau, Refactor".
Haruskah saya hanya menulis kode yang mendeteksi bahwa lineSegments Intersect di dalam fungsi CollidesWithLine dan refactor setelah berfungsi? Itu akan bekerja dalam kasus ini karena saya dapat mengakses data dari LineSegment , tetapi bagaimana jika dalam kasus-kasus di mana data semacam itu bersifat pribadi?
sumber
Pada siklus TDD:
Pada fase "make the test pass", Anda seharusnya menulis implementasi paling sederhana yang akan membuat test pass . Untuk membuat lulus ujian Anda, Anda telah memutuskan untuk membuat kolaborator baru untuk menangani logika yang hilang karena mungkin terlalu banyak pekerjaan untuk dimasukkan ke dalam kelas poin Anda untuk membuat lulus ujian Anda. Di situlah masalahnya terletak. Saya kira ujian yang Anda coba lakukan adalah langkah yang terlalu besar . Jadi saya pikir masalahnya ada pada tes Anda sendiri, Anda harus menghapus / berkomentar tes itu, dan mencari tahu tes sederhana yang akan memungkinkan Anda untuk mengambil langkah kecil tanpa memperkenalkan bagian LineSegment.Intersects (LineSegment). Setelah tes lulus, Anda dapat refactorkode Anda (Di sini Anda akan menerapkan prinsip SRP) dengan memindahkan logika baru ini ke metode LineSegment.Intersects (LineSegment). Tes Anda masih akan berlalu karena Anda tidak akan mengubah perilaku apa pun tetapi hanya memindahkan beberapa kode.
Pada solusi desain Anda saat ini
Tetapi bagi saya, Anda memiliki masalah desain yang lebih mendalam di sini adalah bahwa Anda melanggar Prinsip Tanggung Jawab Tunggal . Peran sebuah Point adalah .... menjadi sebuah point, itu saja. Tidak ada kecerdasan dalam menjadi sebuah poin, itu hanya nilai x dan y. Poin adalah tipe nilai . Ini adalah hal yang sama untuk Segmen, segmen adalah tipe nilai yang terdiri dari dua poin. Mereka dapat berisi sedikit "kecerdasan" misalnya untuk menghitung panjangnya berdasarkan posisi poin mereka. Tapi begitulah.
Sekarang memutuskan apakah suatu titik dan suatu segmen bertabrakan, adalah tanggung jawab sepenuhnya pada dirinya sendiri. Dan tentu saja terlalu banyak pekerjaan untuk titik atau segmen untuk menangani sendiri. Itu tidak bisa menjadi bagian dari kelas Point, karena jika tidak Poin akan tahu tentang Segmen. Dan itu tidak dapat menjadi milik Segmen karena Segmen sudah memiliki tanggung jawab untuk mengurus poin dalam segmen tersebut dan mungkin juga menghitung panjang segmen itu sendiri.
Jadi tanggung jawab ini harus dimiliki oleh kelas lain seperti misalnya "PointSegmentCollisionDetector" yang akan memiliki metode seperti:
bool AreInCollision (Poin p, Segmen s)
Dan itu adalah sesuatu yang akan Anda uji secara terpisah dari Poin dan Segmen.
Yang menyenangkan dengan desain itu sekarang Anda bisa memiliki implementasi yang berbeda dari detektor tabrakan Anda. Jadi akan mudah misalnya untuk membuat tolok ukur mesin gim Anda (saya berasumsi Anda sedang menulis gim: p) dengan mengganti metode pendeteksian tabrakan saat runtime. Atau untuk melakukan beberapa pengecekan visual / eksperimen saat runtime antara berbagai strategi pendeteksian benturan.
Pada saat ini, dengan meletakkan logika ini di kelas poin Anda, Anda mengunci banyak hal dan terlalu banyak memikul tanggung jawab pada kelas Poin.
Semoga masuk akal,
sumber
Hal termudah untuk dilakukan dalam mode TDD adalah mengekstrak antarmuka untuk LineSegment dan mengubah parameter metode Anda untuk mengambil antarmuka. Kemudian Anda bisa mengejek segmen jalur input dan kode / menguji metode Intersect secara mandiri.
sumber
Dengan jUnit4 Anda dapat menggunakan
@Ignore
anotasi untuk tes yang ingin Anda tunda.Tambahkan Anotasi ke setiap metode yang Anda ingin tunda, dan lanjutkan menulis tes untuk fungsionalitas yang diperlukan. Lingkari kembali untuk memperbaiki kasus uji yang lebih lama nanti.
sumber