Rekan kami mempromosikan tes unit penulisan sebagai benar-benar membantu kami untuk memperbaiki hal-hal desain dan refactor kami, tetapi saya tidak mengerti caranya. Jika saya memuat file CSV dan menguraikannya, bagaimana uji unit (memvalidasi nilai di bidang) akan membantu saya memverifikasi desain saya? Dia menyebutkan coupling dan modularitas dll. Tetapi bagi saya itu tidak masuk akal - tapi saya tidak punya banyak latar belakang teoretis.
Itu tidak sama dengan pertanyaan yang Anda tandai sebagai duplikat, saya akan tertarik pada contoh aktual bagaimana ini membantu, bukan hanya teori yang mengatakan "itu membantu". Saya suka jawaban di bawah dan komentar tetapi saya ingin belajar lebih banyak.
design
unit-testing
object-oriented-design
Pengguna039402
sumber
sumber
Jawaban:
Unit test tidak hanya memfasilitasi desain, tetapi itu adalah salah satu manfaat utama mereka.
Penulisan uji-pertama mengusir modularitas dan struktur kode bersih.
Ketika Anda menulis tes kode Anda terlebih dahulu, Anda akan menemukan bahwa "kondisi" dari unit kode tertentu secara alami didorong ke dependensi (biasanya melalui mengejek atau bertopik) ketika Anda menganggapnya dalam kode Anda.
"Diberikan kondisi x, perkirakan perilaku y," akan sering menjadi rintisan untuk memasok
x
(yang merupakan skenario di mana tes perlu memverifikasi perilaku komponen saat ini) dany
akan menjadi tiruan, panggilan yang akan diverifikasi di akhir tes (kecuali jika itu "harus kembaliy
," dalam hal tes hanya akan memverifikasi nilai kembali secara eksplisit).Kemudian, setelah unit ini berperilaku seperti yang ditentukan, Anda beralih ke menulis dependensi (untuk
x
dany
) yang Anda temukan.Hal ini membuat penulisan kode modular yang bersih menjadi proses yang sangat mudah dan alami, jika tidak demikian, seringkali mudah untuk mengaburkan tanggung jawab dan perilaku pasangan tanpa disadari.
Tes menulis nanti akan memberi tahu Anda ketika kode Anda terstruktur dengan buruk.
Ketika menulis tes untuk sepotong kode menjadi sulit karena ada terlalu banyak hal untuk di-stub atau diolok-olok, atau karena hal-hal yang terlalu erat digabungkan bersama-sama, Anda tahu Anda memiliki perbaikan untuk dibuat dalam kode Anda.
Ketika "mengubah tes" menjadi beban karena ada begitu banyak perilaku dalam satu unit, Anda tahu Anda memiliki perbaikan untuk dibuat dalam kode Anda (atau hanya dalam pendekatan Anda dalam menulis tes - tetapi ini tidak biasanya terjadi dalam pengalaman saya) .
Ketika skenario Anda menjadi terlalu rumit ( "jika
x
dany
danz
kemudian ...") karena Anda perlu lebih abstrak, Anda tahu Anda memiliki perbaikan untuk membuat dalam kode Anda.Ketika Anda berakhir dengan tes yang sama di dua fixture berbeda karena duplikasi dan redundansi, Anda tahu Anda memiliki perbaikan yang harus dilakukan dalam kode Anda.
Berikut ini adalah pembicaraan yang sangat baik oleh Michael Feathers menunjukkan hubungan yang sangat dekat antara testability dan desain dalam kode (awalnya diposting oleh displayName di komentar). Pembicaraan juga membahas beberapa keluhan umum dan kesalahpahaman tentang desain yang baik dan kemampuan uji pada umumnya.
sumber
Hal yang hebat tentang unit test adalah mereka memungkinkan Anda untuk menggunakan kode Anda bagaimana programmer lain akan menggunakan kode Anda.
Jika kode Anda canggung untuk unit test, maka mungkin akan terasa canggung untuk digunakan. Jika Anda tidak dapat menyuntikkan dependensi tanpa melewati rintangan, maka kode Anda mungkin tidak fleksibel untuk digunakan. Dan jika Anda perlu menghabiskan banyak waktu menyiapkan data atau mencari tahu untuk melakukan apa, kode Anda yang sedang diuji mungkin memiliki terlalu banyak sambungan dan akan sulit untuk dikerjakan.
sumber
Butuh waktu cukup lama bagi saya untuk menyadari, tetapi manfaat sebenarnya (sunting: bagi saya, milage Anda mungkin berbeda) dari melakukan pengembangan yang digerakkan oleh tes ( menggunakan unit test) adalah Anda harus melakukan desain API di depan !
Pendekatan khas untuk pengembangan adalah pertama-tama mencari tahu bagaimana menyelesaikan masalah yang diberikan, dan dengan pengetahuan itu dan desain implementasi awal beberapa cara untuk meminta solusi Anda. Ini mungkin memberikan beberapa hasil yang agak menarik.
Ketika melakukan TDD Anda harus menulis kode yang akan menggunakan solusi Anda. Masukkan parameter, dan output yang diharapkan sehingga Anda dapat memastikan itu benar. Itu pada gilirannya mengharuskan Anda untuk mencari tahu apa yang sebenarnya perlu Anda lakukan, sehingga Anda dapat membuat tes yang bermakna. Kemudian dan baru Anda mengimplementasikan solusi. Ini juga pengalaman saya bahwa ketika Anda tahu persis apa yang seharusnya dicapai kode Anda, itu menjadi lebih jelas.
Kemudian, setelah pengujian unit implementasi membantu Anda memastikan bahwa refactoring tidak merusak fungsi, dan memberikan dokumentasi tentang cara menggunakan kode Anda (yang Anda tahu benar saat tes berlalu!). Tetapi ini adalah yang kedua - manfaat terbesar adalah pola pikir dalam menciptakan kode sejak awal.
sumber
Saya setuju 100% bahwa unit test membantu "membantu kami untuk memperbaiki hal-hal desain dan refactor kami".
Saya bingung apakah mereka membantu Anda melakukan desain awal . Ya, mereka mengungkapkan kelemahan yang jelas, dan apakah memaksa Anda untuk berpikir tentang "bagaimana saya bisa membuat kode diuji"? Ini akan menyebabkan lebih sedikit efek samping, konfigurasi dan pengaturan yang lebih mudah, dll.
Namun, dalam pengalaman saya, tes unit yang terlalu sederhana, ditulis sebelum Anda benar-benar memahami apa yang seharusnya menjadi desain, (memang, itu berlebihan TDD hard-core, tetapi terlalu sering coders menulis tes sebelum mereka berpikir banyak) sering menyebabkan anemia model domain yang mengekspos terlalu banyak internal.
Pengalaman saya dengan TDD adalah beberapa tahun yang lalu, jadi saya tertarik mendengar teknik baru apa yang mungkin membantu dalam menulis tes yang tidak terlalu bias pada desain yang mendasarinya. Terima kasih.
sumber
Uji unit memungkinkan Anda melihat bagaimana antarmuka antar fungsi bekerja, dan sering memberi Anda wawasan tentang cara meningkatkan desain lokal dan desain keseluruhan. Selain itu jika Anda mengembangkan tes unit Anda saat mengembangkan kode Anda, Anda memiliki suite uji regresi siap pakai. Tidak masalah jika Anda mengembangkan UI atau perpustakaan backend.
Setelah program dikembangkan (dengan unit test), saat bug ditemukan, Anda dapat menambahkan tes untuk memastikan bahwa bug sudah diperbaiki.
Saya menggunakan TDD untuk beberapa proyek saya. Saya berupaya keras dalam membuat contoh yang saya tarik dari buku teks atau dari makalah yang dianggap benar, dan menguji kode yang saya kembangkan menggunakan contoh ini. Kesalahpahaman yang saya miliki tentang metode menjadi sangat jelas.
Saya cenderung sedikit lebih longgar daripada beberapa rekan saya, karena saya tidak peduli apakah kode itu ditulis terlebih dahulu atau tes ditulis terlebih dahulu.
sumber
Ketika Anda ingin menguji unit parser Anda mendeteksi nilai pembatasan dengan benar, Anda mungkin ingin lulus satu baris dari file CSV. Untuk membuat tes Anda langsung dan singkat, Anda mungkin ingin mengujinya melalui satu metode yang menerima satu baris.
Ini secara otomatis akan membuat Anda memisahkan pembacaan garis dari membaca nilai individual.
Pada tingkat lain Anda mungkin tidak ingin meletakkan semua jenis file CSV fisik dalam proyek pengujian Anda tetapi melakukan sesuatu yang lebih mudah dibaca, cukup mendeklarasikan string CSV besar di dalam pengujian Anda untuk meningkatkan keterbacaan dan maksud pengujian. Ini akan mengarahkan Anda untuk memisahkan parser Anda dari I / O apa pun yang akan Anda lakukan di tempat lain.
Hanya contoh dasar, mulailah berlatih, Anda akan merasakan keajaiban di beberapa titik (saya punya).
sumber
Sederhananya, penulisan unit test membantu mengekspos kesalahan dalam kode Anda.
Panduan spektakuler untuk menulis kode yang dapat diuji ini , yang ditulis oleh Jonathan Wolter, Russ Ruffer, dan Miško Hevery, berisi banyak contoh tentang bagaimana cacat dalam kode, yang terjadi untuk menghambat pengujian, juga mencegah penggunaan ulang yang mudah dan fleksibilitas dari kode yang sama. Dengan demikian, jika kode Anda dapat diuji, lebih mudah digunakan. Sebagian besar "moral" adalah tips sederhana yang sangat meningkatkan desain kode ( Dependency Injection FTW).
Sebagai contoh: Sangat sulit untuk menguji apakah metode computeStuff beroperasi dengan benar ketika cache mulai mengusir barang. Ini karena Anda harus menambahkan sampah secara manual ke cache hingga "bigCache" hampir penuh.
Namun, ketika kita menggunakan injeksi dependensi, jauh lebih mudah untuk menguji apakah metode computeStuff beroperasi dengan benar ketika cache mulai mengusir barang. Yang kami lakukan adalah membuat tes di mana kami memanggil
new HereIUseDI(buildSmallCache());
Pemberitahuan, kami memiliki kontrol lebih bernuansa objek dan membayar dividen segera.Manfaat serupa dapat diperoleh ketika kode kami membutuhkan data yang biasanya disimpan dalam basis data ... cukup masukkan secara tepat data yang Anda butuhkan.
sumber
Tergantung pada apa yang dimaksud dengan 'Tes Unit', saya tidak berpikir tes Unit tingkat rendah benar-benar memfasilitasi desain yang baik sebanyak tes integrasi tingkat yang sedikit lebih tinggi - tes yang menguji sekelompok pelaku (kelas, fungsi, apa pun) di kode Anda digabungkan dengan benar untuk menghasilkan sejumlah perilaku yang diinginkan yang telah disepakati antara tim pengembangan dan pemilik produk.
Jika Anda dapat menulis tes pada level tersebut, itu mendorong Anda untuk membuat kode yang bagus, logis, seperti API yang tidak memerlukan banyak dependensi gila - keinginan untuk memiliki pengaturan pengujian sederhana secara alami akan mendorong Anda untuk tidak memiliki banyak dependensi gila atau kode ketat digabungkan.
Jangan salah - Tes unit dapat mengarahkan Anda ke desain yang buruk, serta desain yang baik. Saya telah melihat pengembang mengambil sedikit kode yang sudah memiliki desain logis yang bagus dan satu perhatian, dan memisahkannya dan memperkenalkan lebih banyak antarmuka murni untuk tujuan pengujian, dan sebagai hasilnya membuat kode tersebut kurang mudah dibaca dan sulit untuk diubah , dan bahkan mungkin memiliki lebih banyak bug jika pengembang telah memutuskan bahwa memiliki banyak tes unit tingkat rendah berarti mereka tidak harus memiliki tes tingkat yang lebih tinggi. Contoh favorit tertentu adalah bug yang saya perbaiki di mana ada banyak kode yang sangat mudah rusak, 'dapat diuji' berkaitan dengan mendapatkan informasi di dalam dan di luar papan klip. Semua dipecah dan dipisahkan ke tingkat detail yang sangat kecil, dengan banyak antarmuka, banyak mengejek dalam ujian, dan hal-hal menyenangkan lainnya. Hanya satu masalah - tidak ada kode yang benar-benar berinteraksi dengan mekanisme clipboard OS,
Tes unit pasti dapat mendorong desain Anda - tetapi mereka tidak secara otomatis memandu Anda ke desain yang baik. Anda perlu memiliki ide tentang desain yang bagus yang melampaui 'kode ini diuji, oleh karena itu dapat diuji, oleh karena itu bagus'.
Tentu saja jika Anda salah satu dari orang-orang yang 'tes unit' berarti 'tes otomatis apa pun yang tidak didorong melalui UI', maka beberapa dari peringatan itu mungkin tidak begitu relevan - seperti yang saya katakan, saya pikir yang lebih tinggi -tingkat integrasi sering lebih berguna ketika datang untuk mengarahkan desain Anda.
sumber
Tes unit dapat membantu refactoring ketika kode baru melewati semua tes lama .
Katakanlah Anda telah mengimplementasikan bubblesort karena Anda sedang terburu-buru dan tidak peduli dengan kinerja, tetapi sekarang Anda ingin quicksort karena datanya semakin lama. Jika semua tes lulus, semuanya terlihat baik.
Tentu saja tes harus komprehensif untuk membuat pekerjaan ini. Dalam contoh saya, tes Anda mungkin tidak mencakup stabilitas karena itu tidak ada hubungannya dengan bubblesort.
sumber
Saya telah menemukan unit test paling berharga untuk memfasilitasi pemeliharaan proyek jangka panjang. Ketika saya kembali ke proyek setelah berbulan-bulan dan tidak ingat banyak detailnya, menjalankan tes membuat saya tidak merusak barang-barang.
sumber