Saya seorang programmer baru (baru belajar selama sekitar satu tahun) dan dalam tujuan saya untuk menjadi lebih baik, saya baru saja belajar tentang TDD. Saya ingin membiasakan menggunakannya karena tampaknya sangat membantu. Saya ingin memeriksa dan memastikan saya menggunakannya dengan benar.
Apa yang aku lakukan:
- Pikirkan metode baru yang saya butuhkan.
- Buat tes untuk metode itu.
- Tes gagal.
- Menulis metode
- Lulus tes.
- Metode refactor.
- Ulang.
Saya melakukan ini untuk SETIAP metode yang saya tulis, adakah yang harus saya hindari? Kemudian saya biasanya memikirkan cara untuk menguji metode saya yang sudah ada dengan cara atau situasi yang berbeda. Haruskah saya membuat tes-tes baru yang saya pikirkan, atau karena setiap metode sudah memiliki tes sendiri apakah saya tidak perlu repot? Dapatkah saya LEBIH menguji kode saya, saya kira adalah perhatian utama saya dalam menanyakan ini.
EDIT
Juga, ini adalah sesuatu yang saya hanya ingin tahu. Ketika melakukan sesuatu seperti membuat GUI, apakah TDD diperlukan dalam situasi itu? Secara pribadi, saya tidak bisa memikirkan bagaimana saya akan menulis tes untuk itu.
Jawaban:
Apa yang Anda gambarkan sebagai alur kerja tidak menurut saya Roh TDD.
Sinopsis buku Kent Becks di Amazon mengatakan:
TDD praktis
Pengujian otomatis formal, terutama Pengujian Unit, setiap metode di setiap kelas sama buruknya dengan anti-pola dan tidak menguji apa pun. Ada keseimbangan yang bisa didapat. Apakah Anda menulis tes unit untuk setiap
setXXX/getXXX
metode, mereka juga metode!Tes juga dapat membantu menghemat waktu dan uang, tetapi jangan lupa bahwa mereka membutuhkan waktu dan uang untuk dikembangkan dan mereka adalah kode, sehingga biayanya memerlukan waktu dan uang untuk mempertahankannya. Jika mereka berhenti karena kurangnya perawatan maka mereka menjadi tanggung jawab lebih dari manfaat.
Seperti segala sesuatu seperti ini, ada keseimbangan yang tidak dapat didefinisikan oleh siapa pun kecuali diri Anda sendiri. Dogma apa pun itu mungkin lebih salah dan benar.
Metrik yang baik adalah kode yang penting untuk logika bisnis dan harus sering diubah berdasarkan perubahan persyaratan. Hal-hal itu memerlukan tes formal yang otomatis, yang akan menjadi pengembalian investasi yang besar.
Anda akan sangat kesulitan menemukan banyak toko profesional yang berfungsi dengan baik. Tidak masuk akal secara bisnis untuk mengeluarkan uang untuk menguji hal-hal yang untuk semua tujuan praktis tidak akan pernah berubah setelah tes asap sederhana dilakukan. Menulis tes unit otomatis formal untuk
.getXXX/.setXXX
metode adalah contoh utama dari ini, buang-buang waktu.Lihat juga jawaban ini .
sumber
setXXX/getXXX
tidak diperlukan sama sekali :)Anda sangat dekat. Coba pikirkan dengan cara yang sedikit berbeda ini.
Jangan otomatis membuat getter dan setter untuk setiap properti . Jangan memikirkan seluruh metode dan menulis tes untuk mencakup semua fungsionalitas . Cobalah untuk merangkum properti di dalam kelas dan tulis metode untuk memberikan perilaku yang Anda butuhkan. Biarkan metode Anda berkembang menjadi desain yang baik alih-alih mencoba merencanakannya di muka. Ingatlah bahwa TDD adalah proses desain, bukan proses pengujian. Keuntungan yang dimilikinya dibandingkan proses desain lainnya adalah meninggalkan aliran tes regresi otomatis, daripada selembar kertas yang Anda buang ke tempat sampah.
Juga, ingat tiga aturan TDD Paman Bob .
sumber
Beberapa hal untuk ditambahkan ke tanggapan orang lain:
Ada yang namanya over testing. Anda ingin memastikan tes unit Anda tumpang tindih sesedikit mungkin. Tidak ada gunanya memiliki beberapa tes memverifikasi kondisi yang sama di bagian kode yang sama. Di sisi lain, ketika Anda memperbaiki kode produksi Anda dan Anda memiliki banyak tes yang tumpang tindih dengan bagian itu, Anda harus kembali dan memperbaiki semua tes itu. Sedangkan jika mereka tidak tumpang tindih, maka satu perubahan paling banyak hanya akan merusak satu tes.
Hanya karena Anda memikirkan cara yang lebih baik untuk menulis tes, saya tidak akan kembali ke sana dan mulai menulis ulang. Ini akan kembali ke individu-individu yang terus menulis dan menulis ulang kelas / fungsi yang sama karena mereka berusaha membuatnya sempurna. Itu tidak akan pernah sempurna, jadi teruskan. Ketika Anda menemukan metode yang lebih baik, simpan di belakang pikiran Anda (atau tambahkan komentar tes). Lain kali Anda berada di sana, dan Anda melihat manfaat langsung beralih ke cara baru, itulah saatnya untuk refactor. Jika tidak, jika fitur selesai dan Anda pindah dan semuanya berfungsi, biarkan berfungsi.
TDD berfokus pada memberikan nilai langsung, tidak hanya memastikan setiap fungsi dapat diuji. Ketika Anda menambahkan fungsionalitas, mulailah dengan bertanya "apa yang dibutuhkan klien". Kemudian tentukan antarmuka untuk memberikan klien apa yang dibutuhkan. Kemudian laksanakan apa pun untuk lulus ujian. TDD hampir seperti pengujian skenario penggunaan kasus (termasuk semua "bagaimana-jika"), daripada hanya mengkodekan fungsi publik dan menguji masing-masing.
Anda bertanya tentang pengujian kode GUI. Cari pola "Humble Dialog" dan "MVVM". Gagasan di balik kedua hal ini adalah Anda membuat satu set kelas "model tampilan", yang sebenarnya tidak memiliki logika khusus UI. Namun, kelas-kelas ini akan memiliki semua logika bisnis yang biasanya merupakan bagian dari UI Anda dan kelas-kelas ini harus 100% diuji. Yang tersisa adalah shell UI yang sangat tipis dan ya, biasanya shell tersebut dibiarkan tanpa cakupan pengujian, tetapi pada saat itu seharusnya hampir tidak ada logika.
Jika Anda memiliki sebagian besar kode yang ada, seperti yang disarankan beberapa orang lainnya, Anda tidak harus mulai menambahkan unit test secara tuntas di mana-mana. Ini akan membawa Anda selamanya dan Anda tidak akan mendapatkan manfaat dari menambahkan tes unit ke 80% kelas yang stabil dan tidak akan berubah dalam waktu dekat (atau tidak begitu dekat). Namun, untuk pekerjaan baru, saya menemukan menggunakan pengembangan TDD dengan kode SEMUA menjadi sangat bermanfaat. Anda tidak hanya berakhir dengan suite dengan tes otomatis ketika Anda selesai, tetapi pengembangan aktual memiliki manfaat besar:
sumber
Ada beberapa metode yang tidak diuji, yaitu tes-tes itu. Namun, ada sesuatu yang bisa dikatakan untuk beberapa tes yang ditambahkan setelah kode awal telah ditulis, seperti kondisi batas dan nilai-nilai lain sehingga mungkin ada beberapa tes pada metode tunggal.
Meskipun Anda dapat menguji kode Anda secara berlebihan, itu biasanya datang ketika seseorang ingin menguji setiap permutasi input yang mungkin tidak terdengar seperti apa yang Anda lakukan. Misalnya, jika Anda memiliki metode yang mengambil karakter, apakah Anda menulis tes untuk setiap nilai yang mungkin dapat dimasukkan? Itu akan menjadi tempat Anda akan melakukan overtesting, IMO.
sumber
Secara umum Anda melakukannya dengan benar.
Tes adalah kode. Jadi, jika Anda dapat meningkatkan tes, silakan dan refactor. Jika Anda berpikir bahwa tes dapat ditingkatkan, silakan dan ubah. Jangan takut untuk mengganti tes dengan yang lebih baik.
Saya sarankan dalam menguji kode Anda, hindari menentukan bagaimana kode seharusnya melakukan apa yang dilakukannya. Tes harus melihat hasil metode. Ini akan membantu refactoring. Beberapa metode tidak perlu diuji secara eksplisit (yaitu getter dan setter sederhana) karena Anda akan menggunakannya untuk memverifikasi hasil tes lain.
sumber
Pendapat saya tentang TDD adalah bahwa tooling telah menciptakan dunia pengembang gaya 'point and click'. Hanya karena alat membuat rintisan tes untuk setiap metode tidak berarti Anda harus menulis tes untuk setiap metode. Beberapa orang 'mengubah nama' TDD sebagai BDD (pengembangan yang didorong oleh perilaku) di mana tes lebih berbutir besar dan dimaksudkan untuk menguji perilaku kelas, tidak masing-masing metode kecil fiddly.
Jika Anda merancang tes Anda untuk menguji kelas sebagaimana dimaksudkan untuk digunakan, maka Anda mulai mendapatkan beberapa manfaat, terutama ketika Anda mulai menulis tes yang berolahraga sedikit lebih banyak dari setiap metode, terutama ketika Anda mulai menguji interaksi mereka. metode. Saya kira Anda bisa menganggapnya sebagai tes menulis untuk kelas, bukan metode. Bagaimanapun, Anda masih harus menulis 'tes penerimaan' yang menggunakan kombinasi metode untuk memastikan tidak ada kontradiksi atau konflik dalam penggunaannya bersama.
Jangan bingung dengan pengujian TDD - tidak. TDD dirancang agar Anda menulis kode untuk memenuhi kebutuhan Anda, bukan untuk menguji metode. Ini poin yang halus tapi penting yang sering hilang pada orang yang secara buta menulis kode tes untuk setiap metode. Anda harus menulis tes yang memastikan kode Anda melakukan apa yang Anda inginkan, bukan kode yang Anda tulis berfungsi seperti seharusnya.
Ada beberapa tautan bagus ke kanan tentang BDD v TDD. Periksa mereka.
sumber
Ketika Anda mulai belajar TDD, ya, Anda harus secara membabi buta mengikuti pendekatan dogmatis dari tidak menulis satu baris kode kecuali untuk membuat lulus ujian yang gagal, dan menulis hanya cukup ujian untuk gagal (dan gagal untuk alasan yang tepat / diharapkan) .
Setelah Anda mengetahui apa itu TDD, MAKA Anda dapat memutuskan bahwa hal-hal tertentu tidak layak untuk diuji. Ini adalah pendekatan yang sama yang harus Anda ikuti untuk semuanya, dan seni bela diri Jepang menyebutnya " shuhari ". (Tautan ini juga menjelaskan bagaimana seseorang dapat maju melalui tahap-tahap belajar tanpa guru yang, saya kira, adalah bagaimana kebanyakan orang harus belajar.)
sumber
Saya percaya bahwa Anda overtesting.
Saya telah berlatih TDD selama bertahun-tahun, dan menurut pengalaman saya, ketika TDD dilakukan secara efektif, Anda mendapatkan dua manfaat utama:
Berikan umpan balik yang cepat
Khususnya dengan bahasa dinamis, saya dapat menjalankan tes yang relevan dalam waktu kurang dari satu detik. Dan saya memiliki pengamat sistem file yang menjalankan tes ini secara otomatis ketika file sumber diubah pada disk. Jadi saya tidak punya waktu tunggu untuk ujian, dan saya langsung tahu apakah kode yang saya tulis sesuai dengan yang diharapkan. Jadi TDD mengarah ke cara kerja yang sangat efisien.
Aktifkan refactoring
Jika Anda memiliki ruang uji yang baik, Anda dapat dengan aman melakukan refactor, karena Anda mendapatkan wawasan baru tentang bagaimana sistem harus dirancang.
Rangkaian pengujian yang baik memungkinkan Anda untuk memindahkan tanggung jawab dalam kode Anda, dan masih memiliki keyakinan bahwa kode tersebut berfungsi seperti yang diharapkan setelah pindah. Dan Anda harus dapat melakukan ini dengan sedikit perubahan pada kode tes.
Jika Anda menulis tes untuk setiap metode dalam sistem Anda, kemungkinan besar Anda tidak dapat dengan mudah memperbaiki kode Anda, setiap refactor kode Anda akan membutuhkan perubahan besar pada kode tes. Dan bisakah Anda bahkan yakin bahwa kode pengujian masih berfungsi seperti yang diharapkan? Atau apakah Anda secara tidak sengaja memasukkan bug dalam kode pengujian, yang akibatnya mengarah ke bug dalam kode produksi?
Namun, jika Anda, seperti juga disarankan dalam jawaban pdr , fokus pada perilaku daripada metode saat menulis tes, Anda akan memiliki tes yang akan memerlukan perubahan jauh lebih sedikit ketika refactoring sistem.
Atau seperti yang dikatakan Ian Cooper dalam presentasi ini (saya kutip dari ingatan, jadi mungkin tidak dikutip dengan benar):
sumber
Anda harus menguji setiap metode publik .
Tangkapan di sini adalah bahwa jika metode publik Anda sangat kecil, Anda mungkin mengungkapkan terlalu banyak informasi. Praktek umum mengungkapkan setiap properti sebagai
getXXX()
benar - benar merusak enkapsulasi.Jika metode publik Anda benar-benar perilaku kelas, maka Anda harus mengujinya. Jika tidak, itu bukan metode publik yang baik.
EDIT: jawaban pdr jauh lebih lengkap daripada milikku.
sumber