Saya mencoba untuk membungkus kepala saya di sekitar TDD, khususnya bagian pengembangan. Saya telah melihat beberapa buku, tetapi yang saya temukan terutama menangani bagian pengujian - Sejarah NUnit, mengapa pengujian itu baik, Merah / Hijau / Refactor dan cara membuat String Calculator.
Bagus, tapi itu "hanya" Unit Testing, bukan TDD. Secara khusus, saya tidak mengerti bagaimana TDD membantu saya mendapatkan desain yang baik jika saya membutuhkan Desain untuk mulai mengujinya.
Untuk menggambarkan, bayangkan 3 persyaratan ini:
- Katalog perlu memiliki daftar produk
- Katalog harus mengingat produk mana yang dilihat pengguna
- Pengguna harus dapat mencari produk
Pada titik ini, banyak buku menarik kelinci ajaib keluar dari topi dan hanya menyelami "Menguji Layanan Produk", tetapi mereka tidak menjelaskan bagaimana mereka sampai pada kesimpulan bahwa ada Layanan Produk di tempat pertama. Itulah bagian "Pengembangan" dalam TDD yang saya coba pahami.
Harus ada desain yang sudah ada, tetapi hal-hal di luar entitas-layanan (yaitu: Ada Produk, jadi harus ada ProductService) tidak ditemukan di mana pun (misalnya, persyaratan kedua mengharuskan saya memiliki beberapa konsep tentang Pengguna, tetapi di mana saya ingin mengingatkan fungsi ini? Dan apakah Cari fitur dari ProductService atau SearchService yang terpisah? Bagaimana saya tahu mana yang harus saya pilih?)
Menurut SOLID , saya akan membutuhkan UserService, tetapi jika saya mendesain sistem tanpa TDD, saya mungkin berakhir dengan sejumlah Layanan Metode-Tunggal. Bukankah TDD dimaksudkan untuk membuat saya menemukan desain saya di tempat pertama?
Saya adalah pengembang .net, tetapi sumber daya Java juga akan berfungsi. Saya merasa sepertinya tidak ada contoh aplikasi atau buku nyata yang berhubungan dengan lini aplikasi bisnis nyata. Bisakah seseorang memberikan contoh yang jelas yang menggambarkan proses pembuatan desain menggunakan TDD?
Jawaban:
Ide TDD adalah memulai dengan pengujian dan bekerja dari situ. Dengan demikian, untuk mengambil contoh Anda "Katalog perlu memiliki daftar produk" dapat dilihat sebagai memiliki tes "Periksa produk dalam katalog" dan dengan demikian ini adalah tes pertama. Sekarang, apa yang menyimpan katalog? Apa yang menahan suatu produk? Itu adalah bagian berikutnya dan idenya adalah untuk mendapatkan beberapa bagian yang akan menjadi sesuatu seperti ProductService yang akan lahir dari mendapatkan tes pertama yang harus lulus.
Ide TDD adalah untuk memulai dengan tes dan kemudian menulis kode yang membuat tes lulus sebagai poin pertama. Unit test adalah bagian dari ini ya, tetapi Anda tidak melihat gambaran keseluruhan yang dibentuk dengan memulai dengan tes dan kemudian menulis kode sehingga tidak ada titik buta pada saat ini karena belum ada kode apa pun.
Tutorial Pengembangan Tes Didorong di mana slide 20-22 adalah yang utama. Idenya adalah untuk mengetahui fungsi apa yang harus dilakukan sebagai hasilnya, menulis tes untuk itu dan kemudian membangun solusi. Bagian desain akan bervariasi tergantung pada apa yang diperlukan itu mungkin atau mungkin tidak mudah dilakukan. Poin kuncinya adalah menggunakan TDD dari awal daripada mencoba memperkenalkan terlambat ke dalam proyek. Jika Anda memulai dengan tes terlebih dahulu, ini dapat membantu dan kemungkinan perlu diperhatikan. Jika Anda mencoba menambahkan tes nanti, itu menjadi sesuatu yang dapat ditunda atau ditunda. Slide-slide selanjutnya juga dapat bermanfaat.
Manfaat utama TDD adalah bahwa dengan memulai dengan tes, Anda tidak terkunci ke dalam desain pada awalnya. Dengan demikian, idenya adalah untuk membangun tes dan membuat kode yang akan lulus tes tersebut sebagai metodologi pengembangan. Sebuah Desain Besar di Depan dapat menyebabkan masalah karena ini memberikan ide untuk mengunci sesuatu pada tempatnya yang membuat sistem yang dibangun menjadi kurang gesit pada akhirnya.
Robert Harvey menambahkan ini dalam komentar yang layak untuk disebutkan dalam jawabannya:
sumber
Untuk apa nilainya, TDD membantu saya mencapai desain terbaik lebih cepat daripada tidak melakukan TDD. Saya mungkin akan datang ke desain terbaik dengan atau tanpa itu. Tetapi waktu itu saya akan menghabiskan memikirkannya dan mengambil beberapa tusukan pada kode dihabiskan menulis tes sebagai gantinya. Dan ini lebih sedikit waktu. Untuk saya. Tidak untuk semua orang. Dan, bahkan jika itu mengambil jumlah waktu yang sama, itu akan meninggalkan saya dengan serangkaian tes, sehingga refactoring akan lebih aman, mengarah ke kode yang lebih baik di telepon.
Bagaimana cara melakukannya?
Pertama, ini mendorong saya untuk memikirkan setiap kelas sebagai layanan untuk beberapa kode klien. Kode yang lebih baik berasal dari memikirkan tentang bagaimana kode panggilan ingin menggunakan API daripada khawatir tentang bagaimana kode itu sendiri akan terlihat.
Kedua, itu menghentikan saya menulis terlalu banyak kompleksitas siklometik ke dalam satu metode, sementara saya memikirkannya. Setiap jalur tambahan melalui metode akan cenderung menggandakan jumlah tes yang perlu saya lakukan. Kemalasan semata-mata menyatakan bahwa setelah saya menambahkan terlalu banyak logika, dan saya harus menulis 16 tes untuk menambahkan satu syarat, sekarang saatnya untuk menarik sebagian ke dalam metode / kelas lain dan mengujinya secara terpisah.
Sangat sederhana. Itu bukan alat desain ajaib.
sumber
Persyaratan ini harus dinyatakan kembali dalam istilah manusia. Siapa yang ingin tahu produk mana yang dilihat pengguna sebelumnya? Pengguna? Seorang tenaga penjualan?
Bagaimana? Dengan nama? Dengan merek? Langkah pertama dalam pengembangan yang digerakkan oleh tes adalah menentukan tes, misalnya:
>
Jika ini adalah satu-satunya persyaratan, saya pasti tidak akan melompat untuk membuat ProductService. Saya mungkin membuat halaman web yang sangat sederhana dengan daftar produk statis. Itu akan bekerja dengan sempurna sampai Anda mendapatkan persyaratan untuk menambah dan menghapus produk. Pada titik itu saya mungkin memutuskan paling sederhana untuk menggunakan database relasional dan ORM, dan membuat kelas Produk yang dipetakan ke satu tabel. Masih tidak ada ProductService. Kelas-kelas seperti ProductService akan dibuat kapan dan jika dibutuhkan. Mungkin ada beberapa permintaan web yang perlu melakukan kueri atau pembaruan yang sama. Kemudian kelas ProductService akan dibuat untuk mencegah duplikasi kode.
Singkatnya, TDD mendorong kode untuk ditulis. Desain terjadi saat Anda membuat pilihan implementasi, dan kemudian mengubah kode menjadi kelas untuk menghilangkan duplikasi dan mengontrol dependensi. Saat Anda menambahkan kode, Anda harus membuat kelas baru untuk menjaga kode SOLID. Tetapi Anda tidak perlu memutuskan sebelumnya bahwa Anda akan membutuhkan kelas Produk dan kelas ProductService. Anda mungkin menemukan bahwa hidup ini baik-baik saja hanya dengan kelas Produk.
sumber
ProductService
. Tetapi bagaimana TDD memberi tahu Anda bahwa Anda membutuhkan database dan ORM?Orang lain mungkin tidak setuju, tetapi bagi saya banyak metodologi baru bergantung pada asumsi bahwa pengembang akan melakukan sebagian besar dari apa yang metodologi lama katakan hanya karena kebiasaan atau kebanggaan pribadi, bahwa pengembang biasanya melakukan sesuatu yang cukup jelas. bagi mereka, dan pekerjaan tersebut dikemas dalam bahasa yang bersih atau bagian yang lebih bersih dari bahasa yang agak berantakan sehingga Anda dapat melakukan semua bisnis pengujian.
Beberapa contoh di mana saya mengalami ini di masa lalu:
Ambil sekelompok kontraktor pekerjaan khusus dan beri tahu mereka bahwa tim mereka Agile and Test First. Mereka sering tidak memiliki kebiasaan selain untuk bekerja secara spesifik dan mereka tidak peduli dengan kualitas pekerjaan selama itu berlangsung cukup lama untuk menyelesaikan proyek.
Cobalah dan lakukan sesuatu tes baru terlebih dahulu, habiskan sebagian besar waktu Anda untuk melakukan tes ripping ketika Anda menemukan berbagai pendekatan dan antarmuka adalah omong kosong.
Kode sesuatu tingkat rendah dan baik ditampar karena kurangnya cakupan, atau menulis banyak tes yang tidak berarti banyak karena Anda tidak dapat mengejek perilaku mendasar Anda terikat.
Jika Anda melakukan TDD dan itu berfungsi untuk Anda, bagus untuk Anda, tetapi ada banyak hal (seluruh pekerjaan, atau tahapan proyek) di luar sana di mana ini hanya tidak menambah nilai.
Contoh Anda terdengar seperti Anda bahkan belum ke desain, jadi Anda perlu memiliki percakapan arsitektur, atau Anda membuat prototipe. Anda harus melewati beberapa dari itu terlebih dahulu menurut saya.
sumber
Saya yakin bahwa TDD adalah pendekatan yang sangat berharga untuk desain rinci sistem - yaitu API dan model objek. Namun, untuk sampai ke titik dalam proyek di mana Anda akan mulai menggunakan TDD, Anda harus memiliki gambaran besar dari desain yang sudah dimodelkan dalam beberapa mode dan Anda perlu memiliki gambaran besar dari arsitektur yang sudah dimodelkan dalam beberapa mode. @ user414076 parafrase Robert Martin memiliki ide desain dalam pikiran, tetapi tidak menikah dengannya. Persis. Kesimpulan - TDD bukan satu-satunya kegiatan desain yang sedang berlangsung, ini adalah bagaimana detail dari desain disempurnakan. TDD harus didahului oleh kegiatan desain lain dan masuk ke dalam pendekatan keseluruhan (seperti Agile) yang membahas bagaimana desain keseluruhan akan dibuat dan berevolusi.
FYI - dua buku yang saya rekomendasikan pada topik yang memberikan contoh nyata dan realistis:
Tumbuh Perangkat Lunak Berorientasi Objek, Dipandu oleh Tes - menjelaskan dan memberikan contoh proyek penuh. Ini adalah buku tentang desain, bukan pengujian . Pengujian digunakan sebagai sarana untuk menentukan perilaku yang diharapkan selama kegiatan desain.
pengembangan berbasis tes Panduan Praktis - berjalan lambat dan langkah demi langkah melalui pengembangan aplikasi yang lengkap, walaupun kecil.
sumber
TTD mendorong penemuan desain dengan kegagalan pengujian, bukan kesuksesan, oleh karena itu Anda dapat menguji yang tidak diketahui dan mengulangi secara berulang karena tidak diketahui yang akhirnya mengarah pada rangkaian lengkap unit test - hal yang sangat bagus untuk pemeliharaan berkelanjutan dan hal yang sangat sulit untuk dicoba. retrofit setelah kode ditulis / dirilis.
Sebagai contoh, suatu persyaratan mungkin bahwa input dapat dalam beberapa format berbeda, belum semuanya diketahui. Dengan menggunakan TDD, Anda harus terlebih dahulu menulis tes yang memverifikasi output yang sesuai diberikan dengan format input apa pun . Jelas tes ini akan gagal, jadi Anda menulis kode untuk menangani format yang dikenal dan tes ulang. Karena format yang tidak diketahui diekspos melalui pengumpulan persyaratan, tes baru ditulis sebelum kode ditulis, ini juga harus gagal. Kemudian kode baru ditulis untuk mendukung format baru dan semua tes dijalankan kembali mengurangi peluang untuk regresi.
Juga bermanfaat untuk menganggap unit failure sebagai kode "belum selesai" alih-alih kode "rusak". TDD memungkinkan untuk unit yang belum selesai (kegagalan yang diharapkan), tetapi mengurangi terjadinya unit yang rusak (kegagalan yang tidak terduga).
sumber
Dalam pertanyaan itu dinyatakan:
Mereka sampai pada kesimpulan itu dengan memikirkan bagaimana mereka akan menguji produk ini. "Produk apa yang melakukan ini?" "Yah, kita bisa membuat layanan". "Oke, mari kita menulis tes untuk layanan seperti itu"
sumber
Fungsionalitas dapat memiliki banyak desain dan TDD tidak akan sepenuhnya memberi tahu Anda mana yang terbaik. Bahkan, jika pengujian akan membantu Anda membangun lebih banyak kode modular, ini juga dapat mengarahkan Anda untuk membuat modul yang sesuai dengan persyaratan pengujian dan bukan realitas produksi. Jadi, Anda harus memahami ke mana Anda akan pergi dan bagaimana segala sesuatunya harus sesuai dengan keseluruhan gambar. Jika tidak, ada persyaratan Fungsional dan Non-Fungsional, jangan lupa yang terakhir.
Mengenai desain, saya merujuk pada buku Robert C. Martin (Agile Development) tetapi juga Martin Fowler's Patterns of Arsitektur Aplikasi Perusahaan dan Desain Driver Domain. Yang belakangan terutama sangat sistematis dalam mengekstraksi Entitas dan Hubungan dari persyaratan.
Kemudian, ketika Anda mendapatkan perasaan yang baik tentang opsi yang tersedia untuk Anda tentang cara mengelola entitas tersebut, Anda bisa memberi Anda pendekatan TDD.
sumber
Tidak.
Bagaimana Anda bisa menguji sesuatu yang belum Anda rancang terlebih dahulu?
Ini bukan persyaratan, ini adalah definisi data. Saya tidak tahu apa urusan perangkat lunak Anda, tetapi tidak mungkin analis berbicara seperti itu.
Anda perlu tahu apa saja invarian dari sistem Anda.
Suatu persyaratan akan menjadi seperti:
Jadi jika ini adalah satu-satunya persyaratan, Anda mungkin memiliki kelas seperti:
Kemudian menggunakan TDD, Anda akan menulis test case sebelum menerapkan metode order ().
Jadi tes kedua akan gagal, maka Anda dapat menerapkan metode order () sesuka Anda.
sumber
Anda cukup benar TDD akan menghasilkan implementasi yang baik dari desain yang diberikan. Ini tidak akan membantu proses desain Anda.
sumber
TDD banyak membantu, namun ada bagian penting dalam pengembangan perangkat lunak. Pengembang harus mendengarkan kode yang sedang ditulis. Refactoring adalah bagian ke-3 dalam siklus TDD. Ini adalah langkah utama di mana pengembang harus fokus dan berpikir sebelum pergi ke tes merah berikutnya. Apakah ada duplikasi? Apakah prinsip SOLID diterapkan? Bagaimana dengan kohesi tinggi dan kopling rendah? Bagaimana dengan nama? Lihatlah lebih dekat pada kode yang muncul dari tes dan lihat apakah ada sesuatu yang perlu diubah, didesain ulang. Mempertanyakan kode dan kode akan memberi tahu Anda, bagaimana ia ingin dirancang. Saya biasanya menulis beberapa tes, memeriksa daftar itu dan membuat desain sederhana pertama, tidak perlu "final", biasanya tidak, karena itu berubah ketika menambahkan tes baru. Di situlah desain datang.
sumber