Dapatkah pengujian unit berhasil ditambahkan ke proyek produksi yang ada? Jika demikian, bagaimana dan apakah itu layak?

140

Saya sangat mempertimbangkan untuk menambahkan pengujian unit ke proyek yang ada yang ada di produksi. Itu dimulai 18 bulan yang lalu sebelum saya benar-benar bisa melihat manfaat dari TDD (face palm) , jadi sekarang ini solusi yang agak besar dengan sejumlah proyek dan saya tidak tahu harus mulai dari mana menambahkan tes unit. Apa yang membuat saya mempertimbangkan hal ini adalah bahwa kadang-kadang bug lama muncul kembali, atau bug diperiksa sebagai diperbaiki tanpa benar - benar diperbaiki. Pengujian unit akan mengurangi atau mencegah masalah ini terjadi.

Dengan membaca pertanyaan serupa di SO, saya telah melihat rekomendasi seperti mulai dari pelacak bug dan menulis uji kasus untuk setiap bug untuk mencegah regresi. Namun, saya khawatir bahwa pada akhirnya saya akan kehilangan gambaran besarnya dan berakhir dengan melewatkan tes fundamental yang akan disertakan jika saya menggunakan TDD sejak awal.

Apakah ada proses / langkah yang harus dipatuhi untuk memastikan bahwa solusi yang ada diuji dengan benar dan tidak hanya diikutsertakan? Bagaimana saya bisa memastikan bahwa tes-tes itu berkualitas baik dan bukan hanya kasus tes apa pun yang lebih baik daripada tidak ada tes .

Jadi saya kira apa yang juga saya tanyakan adalah;

  • Apakah sepadan dengan upaya untuk solusi yang ada yang ada di produksi?
  • Apakah lebih baik untuk mengabaikan pengujian untuk proyek ini dan menambahkannya dalam kemungkinan menulis ulang di masa depan?
  • Apa yang akan lebih bermanfaat; menghabiskan beberapa minggu menambahkan tes atau beberapa minggu menambahkan fungsionalitas?

(Jelas jawaban untuk poin ketiga sepenuhnya tergantung pada apakah Anda berbicara dengan manajemen atau pengembang)


Alasan Bounty

Menambahkan karunia untuk mencoba dan menarik berbagai jawaban yang lebih luas yang tidak hanya mengkonfirmasi kecurigaan saya yang ada bahwa itu adalah hal yang baik untuk dilakukan, tetapi juga beberapa alasan bagus untuk menentang.

Saya bermaksud untuk menulis pertanyaan ini nanti dengan pro dan kontra untuk mencoba dan menunjukkan kepada manajemen bahwa ada baiknya menghabiskan waktu berjam-jam untuk memindahkan pengembangan produk di masa depan ke TDD. Saya ingin mendekati tantangan ini dan mengembangkan alasan saya tanpa sudut pandang saya sendiri yang bias.

djdd87
sumber
11
Tautan wajib ke buku Michael Feathers tentang topik: amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/…
Mark Rushakoff
1
@ Mark - Terima kasih, ada di tautan yang saya berikan. Saya berharap mendapat jawaban yang layak tanpa membeli buku lain ... walaupun Anda tidak akan pernah memiliki terlalu banyak buku (kecuali jika Anda ingin menyelesaikan pekerjaan itu).
djdd87
1
Anda benar-benar perlu membaca buku ini :) Ini adalah salah satu favorit saya dan sangat membantu untuk memahami ketegangan antara refactoring dan pengujian otomatis.
manuel aldana

Jawaban:

177

Saya telah memperkenalkan unit test ke basis kode yang tidak memilikinya sebelumnya. Proyek besar terakhir yang saya lakukan di mana saya melakukan ini adalah produknya sudah di produksi dengan nol unit test ketika saya tiba di tim. Ketika saya pergi - 2 tahun kemudian - kami memiliki 4.500+ tes yang menghasilkan sekitar 33% cakupan kode dalam basis kode dengan 230.000+ LOC produksi (aplikasi Win-Forms finansial waktu nyata). Itu mungkin terdengar rendah, tetapi hasilnya adalah peningkatan yang signifikan dalam kualitas kode dan tingkat cacat - ditambah peningkatan moral dan profitabilitas.

Ini bisa dilakukan ketika Anda memiliki pemahaman dan komitmen yang akurat dari pihak-pihak yang terlibat.

Pertama-tama, penting untuk memahami bahwa pengujian unit adalah keterampilan itu sendiri. Anda bisa menjadi programmer yang sangat produktif dengan standar "konvensional" dan masih kesulitan untuk menulis tes unit dengan cara yang skala dalam proyek yang lebih besar.

Juga, dan khusus untuk situasi Anda, menambahkan unit test ke basis kode yang ada yang tidak memiliki tes juga merupakan keahlian khusus. Kecuali jika Anda atau seseorang dalam tim Anda memiliki pengalaman sukses dengan memperkenalkan tes unit ke basis kode yang ada, saya akan mengatakan membaca buku Feather adalah persyaratan (tidak opsional atau sangat disarankan).

Membuat transisi ke unit menguji kode Anda adalah investasi pada orang dan keterampilan sama halnya dengan kualitas basis kode. Memahami ini sangat penting dalam hal pola pikir dan mengelola harapan.

Sekarang, untuk komentar dan pertanyaan Anda:

Namun, saya khawatir bahwa pada akhirnya saya akan kehilangan gambaran besarnya dan berakhir dengan melewatkan tes fundamental yang akan disertakan jika saya menggunakan TDD sejak awal.

Jawaban singkat: Ya, Anda akan melewatkan tes dan ya mereka mungkin awalnya tidak terlihat seperti apa yang akan mereka miliki dalam situasi lapangan hijau.

Jawaban level yang lebih dalam adalah ini: Tidak masalah. Anda mulai tanpa tes. Mulai menambahkan tes, dan refactor saat Anda pergi. Ketika tingkat keterampilan menjadi lebih baik, mulailah menaikkan bilah untuk semua kode baru yang ditambahkan ke proyek Anda. Terus tingkatkan dll ...

Sekarang, dengan membaca yang tersirat di sini saya mendapat kesan bahwa ini datang dari pola pikir "kesempurnaan sebagai alasan untuk tidak mengambil tindakan". Pola pikir yang lebih baik adalah fokus pada kepercayaan diri. Jadi karena Anda mungkin belum tahu cara melakukannya, Anda akan mencari cara melakukannya dan mengisi bagian yang kosong. Karena itu, tidak ada alasan untuk khawatir.

Sekali lagi, ini keterampilan. Anda tidak dapat beralih dari nol tes ke kesempurnaan TDD dalam satu "proses" atau "langkah demi langkah" pendekatan buku masak secara linear. Ini akan menjadi proses. Harapan Anda harus membuat kemajuan dan peningkatan bertahap dan bertahap. Tidak ada pil ajaib.

Berita baiknya adalah ketika bulan-bulan (dan bahkan bertahun-tahun) berlalu, kode Anda akan secara bertahap mulai menjadi kode yang "layak" diperhitungkan dengan baik dan teruji dengan baik.

Sebagai catatan. Anda akan menemukan bahwa hambatan utama untuk memperkenalkan unit test dalam basis kode lama adalah kurangnya kohesi dan ketergantungan yang berlebihan. Karena itu, Anda mungkin akan menemukan bahwa keterampilan yang paling penting adalah bagaimana memecahkan dependensi yang ada dan kode decoupling, daripada menulis unit test yang sebenarnya sendiri.

Apakah ada proses / langkah yang harus dipatuhi untuk memastikan bahwa solusi yang ada diuji dengan benar dan tidak hanya diikutsertakan?

Kecuali Anda sudah memilikinya, buat server build dan atur pembangunan integrasi berkelanjutan yang berjalan di setiap checkin termasuk semua tes unit dengan cakupan kode.

Latih orang Anda.

Mulai di suatu tempat dan mulai menambahkan tes saat Anda membuat kemajuan dari perspektif pelanggan (lihat di bawah).

Gunakan cakupan kode sebagai referensi panduan tentang seberapa banyak basis kode produksi Anda sedang diuji.

Waktu pembangunan harus selalu CEPAT. Jika waktu pembuatan Anda lambat, keterampilan pengujian unit Anda tertinggal. Temukan tes lambat dan tingkatkan (pisahkan kode produksi dan uji secara terpisah). Ditulis dengan baik, Anda seharusnya dapat memiliki beberapa ribu unit test dan masih menyelesaikan build di bawah 10 menit (~ 1-beberapa ms / test adalah pedoman yang bagus tapi sangat kasar, beberapa pengecualian mungkin berlaku seperti kode menggunakan refleksi dll) ).

Periksa dan beradaptasi.

Bagaimana saya bisa memastikan bahwa tes-tes itu berkualitas baik dan bukan hanya kasus tes apa pun yang lebih baik daripada tidak ada tes.

Penilaian Anda sendiri harus menjadi sumber utama realitas Anda. Tidak ada metrik yang dapat menggantikan keterampilan.

Jika Anda tidak memiliki pengalaman atau penilaian itu, pertimbangkan untuk mengontrak seseorang yang memilikinya.

Dua indikator sekunder kasar adalah cakupan kode total dan kecepatan bangun.

Apakah sepadan dengan upaya untuk solusi yang ada yang ada di produksi?

Iya. Sebagian besar uang yang dihabiskan untuk sistem atau solusi yang dibuat khusus dihabiskan setelah dimasukkan ke dalam produksi. Dan berinvestasi dalam kualitas, orang, dan keterampilan tidak boleh ketinggalan zaman.

Apakah lebih baik untuk mengabaikan pengujian untuk proyek ini dan menambahkannya dalam kemungkinan menulis ulang di masa depan?

Anda harus mempertimbangkan, tidak hanya investasi pada orang dan keterampilan, tetapi yang paling penting total biaya kepemilikan dan waktu hidup yang diharapkan dari sistem.

Jawaban pribadi saya akan "ya tentu saja" dalam sebagian besar kasus karena saya tahu itu jauh lebih baik, tetapi saya menyadari bahwa mungkin ada pengecualian.

Apa yang akan lebih bermanfaat; menghabiskan beberapa minggu menambahkan tes atau beberapa minggu menambahkan fungsionalitas?

Tidak juga. Pendekatan Anda harus menambahkan tes ke basis kode Anda SAAT Anda membuat kemajuan dalam hal fungsionalitas.

Sekali lagi, ini merupakan investasi pada orang, keterampilan DAN kualitas basis kode dan karena itu akan membutuhkan waktu. Anggota tim perlu belajar cara memecahkan ketergantungan, menulis tes unit, mempelajari kebiasaan baru, meningkatkan disiplin dan kesadaran kualitas, cara merancang perangkat lunak yang lebih baik, dll. Penting untuk dipahami bahwa ketika Anda mulai menambahkan tes, anggota tim Anda kemungkinan tidak memiliki keterampilan ini namun pada tingkat yang mereka butuhkan agar pendekatan itu berhasil, sehingga menghentikan kemajuan untuk menghabiskan waktu untuk menambahkan banyak tes tidak akan berhasil.

Juga, menambahkan tes unit ke basis kode yang ada dari setiap ukuran proyek yang cukup besar adalah upaya BESAR yang membutuhkan komitmen dan ketekunan. Anda tidak dapat mengubah sesuatu yang mendasar, berharap banyak belajar di jalan, dan meminta sponsor Anda untuk tidak mengharapkan ROI dengan menghentikan aliran nilai bisnis. Itu tidak akan terbang, dan sejujurnya tidak seharusnya.

Ketiga, Anda ingin menanamkan nilai fokus bisnis yang sehat di tim Anda. Kualitas tidak pernah datang dengan mengorbankan pelanggan dan Anda tidak dapat pergi cepat tanpa kualitas. Selain itu, pelanggan hidup dalam dunia yang terus berubah, dan tugas Anda adalah membuatnya lebih mudah beradaptasi. Penyelarasan pelanggan membutuhkan kualitas dan aliran nilai bisnis.

Apa yang Anda lakukan adalah melunasi hutang teknis. Dan Anda melakukannya sambil tetap melayani pelanggan Anda yang selalu berubah kebutuhan. Berangsur-angsur setelah hutang terbayar, situasinya membaik, dan lebih mudah untuk melayani pelanggan dengan lebih baik dan memberikan nilai lebih. Dll. Momentum positif ini adalah apa yang harus Anda tuju karena ini menggarisbawahi prinsip-prinsip langkah berkelanjutan dan akan mempertahankan dan meningkatkan moral - baik untuk tim pengembangan Anda, pelanggan Anda dan pemangku kepentingan Anda.

Semoga itu bisa membantu

Mahol25
sumber
Mencerminkan pola pikir yang sama seperti yang saya miliki. Saat ini saya sedang dalam proses menampilkan proses / metode yang tepat ini untuk memperkenalkan kasus uji dalam aplikasi JAVA Besar. :)
Darshan Joshi
3
Ini adalah jawaban terartikulasi terbaik tentang topik apa pun yang pernah saya baca di Stackoverflow. Sudah selesai dilakukan dengan baik! Jika Anda belum melakukannya, saya ingin Anda mempertimbangkan untuk menulis buku tentang jawaban Anda untuk pertanyaan terakhir.
Yermo Lamers
Yermo terima kasih. Saya tidak yakin apakah saya punya waktu untuk menulis buku. Tapi mungkin saya bisa menulis satu atau dua artikel blog. Baru memulai blog baru saya, jadi mungkin perlu waktu.
Mahol25
2
Saran pengujian unit dudes ini adalah saran kehidupan umum. Serius.
Wjdavis5
24
  • Apakah sepadan dengan upaya untuk solusi yang ada yang ada di produksi?

Iya!

  • Apakah lebih baik untuk mengabaikan pengujian untuk proyek ini dan menambahkannya dalam kemungkinan menulis ulang di masa depan?

Tidak!

  • Apa yang akan lebih bermanfaat; menghabiskan beberapa minggu menambahkan tes atau beberapa minggu menambahkan fungsionalitas?

Menambahkan pengujian (terutama pengujian otomatis) membuatnya jauh lebih mudah untuk menjaga proyek tetap berjalan di masa depan, dan itu membuatnya jauh lebih kecil kemungkinannya bahwa Anda akan mengirimkan masalah bodoh kepada pengguna.

Tes untuk dimasukkan ke dalam apriori adalah tes yang memeriksa apakah apa yang Anda yakini sebagai antarmuka publik untuk kode Anda (dan setiap modul di dalamnya) berfungsi seperti yang Anda pikirkan. Jika Anda bisa, cobalah untuk juga menginduksi setiap mode kegagalan terisolasi yang harus dimiliki modul kode Anda (perhatikan bahwa ini bisa non-sepele, dan Anda harus berhati-hati untuk tidak memeriksa terlalu hati-hati bagaimana hal-hal gagal, misalnya, Anda tidak benar-benar ingin untuk melakukan hal-hal seperti menghitung jumlah pesan log yang dihasilkan pada kegagalan, karena memverifikasi bahwa itu dicatat sudah cukup).

Kemudian lakukan tes untuk setiap bug saat ini di basis data bug Anda yang menginduksi persis bug dan yang akan berlalu ketika bug diperbaiki. Kemudian perbaiki bug itu! :-)

Dibutuhkan waktu di depan untuk menambah tes, tetapi Anda dibayar kembali berkali-kali di bagian belakang karena kode Anda pada akhirnya memiliki kualitas yang jauh lebih tinggi. Itu sangat berarti ketika Anda mencoba untuk mengirim versi baru atau melakukan pemeliharaan.

Donal Fellows
sumber
Terima kasih atas tanggapan yang terperinci. Mengonfirmasi apa yang saya rasakan. Akan melihat jawaban lain apa yang diposting sebelum memberikan suara saya dan menerima.
djdd87
15

Masalah dengan pengujian unit retrofit adalah Anda akan menyadari bahwa Anda tidak berpikir untuk menyuntikkan ketergantungan di sini atau menggunakan antarmuka di sana, dan tak lama kemudian Anda akan menulis ulang seluruh komponen. Jika Anda punya waktu untuk melakukan ini, Anda akan membangun sendiri jaring pengaman yang bagus, tetapi Anda bisa saja memperkenalkan bug halus di sepanjang jalan.

Saya telah terlibat dengan banyak proyek yang benar-benar membutuhkan pengujian unit sejak hari pertama, dan tidak ada cara mudah untuk mendapatkannya di sana, singkat dari penulisan ulang lengkap, yang biasanya tidak dapat dibenarkan ketika kode bekerja dan sudah menghasilkan uang. Baru-baru ini, saya terpaksa menulis skrip PowerShell yang menjalankan kode dengan cara yang mereproduksi cacat segera setelah itu dinaikkan dan kemudian menyimpan skrip ini sebagai rangkaian tes regresi untuk perubahan lebih lanjut di telepon. Dengan begitu Anda setidaknya dapat mulai membangun beberapa tes untuk aplikasi tanpa mengubahnya terlalu banyak, namun, ini lebih seperti tes regresi ujung ke ujung daripada tes unit yang tepat.

Pembuat panah
sumber
Jika kode dibagi cukup baik dari awal, cukup mudah untuk mengujinya. Masalahnya muncul ketika Anda memiliki kode yang berantakan semua dijahit bersama dan di mana satu-satunya titik uji yang terbuka adalah untuk tes integrasi penuh. (Saya memiliki kode seperti itu di mana testability hampir nol karena jumlah yang bergantung pada komponen lain yang tidak mudah untuk diejek, dan di mana penyebaran memerlukan reboot server. Diuji ... tetapi sulit dilakukan dengan baik.)
Donal Fellows
13

Saya setuju dengan apa yang dikatakan kebanyakan orang. Menambahkan tes ke kode yang ada sangat berharga. Saya tidak akan pernah setuju dengan hal itu, tetapi saya ingin menambahkan satu peringatan.

Meskipun menambahkan tes ke kode yang ada sangat berharga, itu memang perlu biaya. Itu datang dengan biaya tidak membangun fitur baru. Bagaimana dua hal ini seimbang sepenuhnya tergantung pada proyek, dan ada sejumlah variabel.

  • Berapa lama waktu yang Anda butuhkan untuk menguji semua kode itu? Berhari-hari? Minggu? Bulan? Tahun?
  • Untuk siapa Anda menulis kode ini? Membayar pelanggan? Seorang profesor? Proyek sumber terbuka?
  • Seperti apa jadwalmu? Apakah Anda memiliki tenggat waktu yang sulit yang harus Anda penuhi? Apakah Anda punya tenggat waktu sama sekali?

Sekali lagi, izinkan saya menekankan, tes sangat berharga dan Anda harus bekerja untuk menguji kode lama Anda. Ini benar-benar lebih merupakan masalah bagaimana Anda mendekatinya. Jika Anda mampu menghentikan semuanya dan menguji semua kode lama Anda, lakukanlah. Jika itu tidak realistis, inilah yang harus Anda lakukan paling tidak

  • Setiap kode baru yang Anda tulis harus sepenuhnya dalam unit test
  • Kode lama apa pun yang Anda sentuh (perbaikan bug, ekstensi, dll.) Harus dimasukkan dalam unit test

Juga, ini bukan proposisi semua atau tidak sama sekali. Jika Anda memiliki tim, katakanlah, empat orang, dan Anda dapat memenuhi tenggat waktu Anda dengan menempatkan satu atau dua orang pada tugas pengujian warisan, tentu saja lakukan itu.

Edit:

Saya bermaksud untuk menulis pertanyaan ini nanti dengan pro dan kontra untuk mencoba dan menunjukkan kepada manajemen bahwa ada baiknya menghabiskan waktu berjam-jam untuk memindahkan pengembangan produk di masa depan ke TDD.

Ini seperti bertanya "Apa pro dan kontra untuk menggunakan kontrol sumber?" atau "Apa pro dan kontra untuk mewawancarai orang-orang sebelum mempekerjakan mereka?" atau "Apa pro dan kontra untuk bernafas?"

Terkadang hanya ada satu sisi argumen. Anda perlu memiliki tes otomatis dari beberapa bentuk untuk setiap proyek dengan kompleksitas apa pun. Tidak, tes tidak menulis sendiri, dan, ya, akan butuh sedikit waktu ekstra untuk menyelesaikannya. Tetapi dalam jangka panjang akan membutuhkan lebih banyak waktu dan biaya lebih banyak uang untuk memperbaiki bug setelah fakta daripada menulis tes di muka. Titik. Itu semua yang ada untuk itu.

haydenmuhl
sumber
9

Ketika kami mulai menambahkan tes, itu ke basis kode sepuluh tahun, sekitar juta-line, dengan terlalu banyak logika di UI dan dalam kode pelaporan.

Salah satu hal pertama yang kami lakukan (setelah menyiapkan server pembangunan berkelanjutan) adalah menambahkan tes regresi. Ini adalah tes ujung ke ujung.

  • Setiap rangkaian tes dimulai dengan menginisialisasi database ke kondisi yang diketahui. Kami sebenarnya memiliki puluhan dataset regresi yang kami simpan di Subversion (dalam repositori terpisah dari kode kami, karena ukurannya yang tipis). FixtureSetUp setiap tes menyalin salah satu dari set data regresi ini ke dalam temp temp database, dan kemudian berjalan dari sana.
  • Pengaturan perlengkapan uji kemudian menjalankan beberapa proses yang hasilnya menarik bagi kami (Langkah ini opsional - beberapa tes regresi hanya ada untuk menguji laporan.)
  • Kemudian setiap tes menjalankan laporan, menampilkan laporan ke file .csv, dan membandingkan konten .csv itu dengan snapshot yang disimpan. Snapshot .csv ini disimpan dalam Subversion di sebelah setiap dataset regresi. Jika output laporan tidak sesuai dengan snapshot yang disimpan, tes gagal.

Tujuan dari tes regresi adalah untuk memberi tahu Anda jika ada perubahan. Itu berarti mereka gagal jika Anda memecahkan sesuatu, tetapi mereka juga gagal jika Anda mengubah sesuatu dengan sengaja (dalam hal ini perbaikannya adalah memperbarui file snapshot). Anda tidak tahu bahwa file snapshot bahkan benar - mungkin ada bug dalam sistem (dan kemudian ketika Anda memperbaiki bug itu, tes regresi akan gagal).

Namun demikian, tes regresi adalah kemenangan besar bagi kami. Hampir semua yang ada di sistem kami memiliki laporan, jadi dengan menghabiskan beberapa minggu mendapatkan test harness di sekitar laporan, kami dapat memperoleh beberapa tingkat jangkauan atas sebagian besar basis kode kami. Menulis tes unit yang setara akan memakan waktu berbulan-bulan atau bertahun-tahun. (Tes unit akan memberi kami cakupan yang jauh lebih baik, dan akan jauh lebih rapuh; tetapi saya lebih suka memiliki sesuatu sekarang, daripada menunggu bertahun-tahun untuk kesempurnaan.)

Kemudian kami kembali dan mulai menambahkan tes unit ketika kami memperbaiki bug, atau menambahkan perangkat tambahan, atau perlu memahami beberapa kode. Tes regresi sama sekali tidak menghilangkan kebutuhan untuk tes unit; mereka hanya jaring pengaman tingkat pertama, sehingga Anda mendapatkan beberapa tingkat cakupan tes dengan cepat. Kemudian Anda dapat mulai refactoring untuk memutus ketergantungan, sehingga Anda dapat menambahkan tes unit; dan tes regresi memberi Anda tingkat kepercayaan bahwa refactoring Anda tidak merusak apa pun.

Tes regresi memiliki masalah: mereka lambat, dan ada terlalu banyak alasan mengapa mereka bisa pecah. Tapi setidaknya bagi kami, mereka sangat berharga. Mereka telah menangkap bug yang tak terhitung jumlahnya selama lima tahun terakhir, dan mereka menangkapnya dalam beberapa jam, daripada menunggu siklus QA. Kami masih memiliki tes regresi orisinal itu, tersebar di tujuh mesin pembangunan berkelanjutan yang berbeda (terpisah dari yang menjalankan pengujian unit cepat), dan kami bahkan menambahkannya dari waktu ke waktu, karena kami masih memiliki begitu banyak kode sehingga 6.000 kami + unit test tidak mencakup.

Joe White
sumber
8

Ini sangat berharga. Aplikasi kami memiliki aturan validasi silang yang kompleks, dan kami baru-baru ini harus membuat perubahan signifikan pada aturan bisnis. Kami berakhir dengan konflik yang mencegah pengguna menyimpan. Saya menyadari akan membutuhkan waktu lama untuk mengatasinya di applcation (perlu beberapa menit hanya untuk sampai ke titik di mana masalahnya). Saya ingin memperkenalkan tes unit otomatis dan kerangka diinstal, tetapi saya tidak melakukan apa pun di luar beberapa tes boneka untuk memastikan semuanya bekerja. Dengan aturan bisnis baru di tangan, saya mulai menulis tes. Tes dengan cepat mengidentifikasi kondisi yang menyebabkan konflik, dan kami dapat memperjelas aturan.

Jika Anda menulis tes yang mencakup fungsionalitas yang Anda tambahkan atau modifikasi, Anda akan mendapatkan manfaat langsung. Jika Anda menunggu penulisan ulang, Anda mungkin tidak akan pernah memiliki tes otomatis.

Anda seharusnya tidak menghabiskan banyak waktu menulis tes untuk hal-hal yang sudah ada yang berfungsi. Sebagian besar waktu, Anda tidak memiliki spesifikasi untuk kode yang ada, jadi hal utama yang Anda uji adalah kemampuan rekayasa balik Anda. Di sisi lain, jika Anda akan memodifikasi sesuatu, Anda perlu membahas fungsionalitas itu dengan tes sehingga Anda akan tahu Anda membuat perubahan dengan benar. Dan tentu saja, untuk fungsionalitas baru, tulis tes yang gagal, lalu terapkan fungsionalitas yang hilang.

Hugh Brackett
sumber
6

Saya akan menambahkan suara saya dan berkata ya, itu selalu berguna!

Ada beberapa perbedaan yang harus Anda ingat: kotak hitam vs kotak putih, dan unit vs fungsional. Karena definisi berbeda, inilah yang saya maksud dengan ini:

  • Black-box = tes yang ditulis tanpa pengetahuan khusus tentang implementasi, biasanya mencari-cari di tepi kasus untuk memastikan hal-hal terjadi seperti yang diharapkan oleh pengguna yang naif.
  • White-box = tes yang ditulis dengan pengetahuan implementasi, yang sering mencoba untuk melatih poin kegagalan yang terkenal.
  • Tes unit = tes unit individual (fungsi, modul yang dapat dipisahkan, dll). Misalnya: memastikan kelas array Anda berfungsi seperti yang diharapkan, dan bahwa fungsi perbandingan string Anda mengembalikan hasil yang diharapkan untuk berbagai input.
  • Tes fungsional = tes seluruh sistem sekaligus. Tes ini akan menjalankan sebagian besar sistem sekaligus. Misalnya: init, buka koneksi, lakukan beberapa hal di dunia nyata, tutup, akhiri. Saya suka menggambar perbedaan antara ini dan tes unit, karena mereka melayani tujuan yang berbeda.

Ketika saya telah menambahkan tes ke produk pengiriman di akhir permainan, saya menemukan bahwa saya mendapatkan yang terbaik untuk uang dari kotak putih dan tes fungsional . Jika ada bagian dari kode yang Anda tahu sangat rapuh, tulis tes kotak putih untuk membahas kasus-kasus yang bermasalah untuk memastikan tidak rusak dengan cara yang sama dua kali. Demikian pula, tes fungsional seluruh sistem adalah pemeriksaan kewarasan berguna yang membantu Anda memastikan Anda tidak pernah melanggar 10 kasus penggunaan paling umum.

Kotak hitam dan tes unit untuk unit kecil juga berguna, tetapi jika waktu Anda terbatas, lebih baik menambahkannya lebih awal. Pada saat Anda dikirim, Anda biasanya menemukan (dengan cara yang sulit) sebagian besar kasus tepi dan masalah yang akan ditemukan oleh tes ini.

Seperti yang lain, saya juga akan mengingatkan Anda tentang dua hal paling penting tentang TDD:

  1. Membuat tes adalah pekerjaan yang berkelanjutan. Tidak pernah berhenti. Anda harus mencoba menambahkan tes baru setiap kali Anda menulis kode baru, atau memodifikasi kode yang ada.
  2. Test suite Anda tidak pernah salah! Jangan biarkan fakta bahwa Anda menjalani tes menidurkan Anda ke rasa aman yang salah. Hanya karena melewati test suite tidak berarti itu berfungsi dengan benar, atau bahwa Anda belum memperkenalkan regresi kinerja yang halus, dll.
Drew Thaler
sumber
4

Apakah perlu menambahkan uji unit ke aplikasi yang sedang diproduksi tergantung pada biaya pemeliharaan aplikasi. Jika aplikasi memiliki beberapa bug dan permintaan peningkatan, maka mungkin itu tidak sepadan dengan usaha. OTOH, jika aplikasi buggy atau sering dimodifikasi maka unit test akan sangat bermanfaat.

Pada titik ini, ingatlah bahwa saya sedang berbicara tentang menambahkan tes unit secara selektif, tidak mencoba untuk menghasilkan serangkaian tes yang serupa dengan yang akan ada jika Anda telah berlatih TDD dari awal. Karena itu, sebagai tanggapan terhadap bagian kedua dari pertanyaan kedua Anda: jadikan titik untuk menggunakan TDD pada proyek Anda berikutnya, apakah itu proyek baru atau penulisan ulang (permintaan maaf, tapi di sini ada tautan ke buku lain yang benar-benar harus Anda baca : Growing Object Oriented Software Dipandu oleh Tes )

Jawaban saya untuk pertanyaan ketiga Anda sama dengan yang pertama: itu tergantung pada konteks proyek Anda.

Tertanam dalam posting Anda adalah pertanyaan lebih lanjut tentang memastikan bahwa setiap pengujian retro-pas dilakukan dengan benar . Hal yang penting untuk dipastikan adalah bahwa unit test benar-benar merupakan unit unit , dan ini (lebih sering daripada tidak) berarti bahwa tes perkuatan memerlukan refactoring kode yang ada untuk memungkinkan decoupling dari lapisan / komponen Anda (lih. Ketergantungan injeksi; inversi kontrol; stubbing; mengejek). Jika Anda gagal menegakkan ini maka tes Anda menjadi tes integrasi, yang berguna, tetapi kurang bertarget dan lebih rapuh daripada tes unit yang sebenarnya.

Seb Rose
sumber
4

Anda tidak menyebutkan bahasa implementasi, tetapi jika di Jawa maka Anda bisa mencoba pendekatan ini:

  1. Di pohon terpisah membangun regresi atau tes 'asap', menggunakan alat untuk menghasilkan mereka, yang mungkin membuat Anda dekat dengan cakupan 80%. Tes-tes ini mengeksekusi semua jalur logika kode, dan memverifikasi dari titik itu bahwa kode masih melakukan apa yang dilakukannya saat ini (bahkan jika ada bug). Ini memberi Anda jaring pengaman terhadap perilaku yang berubah secara tidak sengaja ketika melakukan refactoring yang diperlukan untuk membuat kode mudah diuji unit dengan tangan.

  2. Untuk setiap bug yang Anda perbaiki, atau fitur yang Anda tambahkan mulai sekarang, gunakan pendekatan TDD untuk memastikan kode baru dirancang agar dapat diuji dan tempatkan tes ini di pohon sumber tes normal.

  3. Kode yang ada juga kemungkinan akan perlu diubah, atau dire-refored agar dapat diuji sebagai bagian dari penambahan fitur baru; tes asap Anda akan memberi Anda jaring pengaman terhadap regresi atau perubahan perilaku yang tidak disengaja.

  4. Saat melakukan perubahan (perbaikan bug atau fitur) melalui TDD, saat selesai sepertinya tes asap pendamping gagal. Verifikasi kegagalan seperti yang diharapkan karena perubahan yang dilakukan dan hapus uji asap yang kurang dapat dibaca, karena tes unit tulisan tangan Anda memiliki cakupan penuh dari komponen yang ditingkatkan itu. Pastikan cakupan pengujian Anda tidak menurun hanya tetap sama atau meningkat.

  5. Saat memperbaiki bug, tulis unit test gagal yang mengekspos bug terlebih dahulu.

Chris B
sumber
3

Saya ingin memulai jawaban ini dengan mengatakan bahwa pengujian unit sangat penting karena akan membantu Anda menangkap bug sebelum merambah ke produksi.

Identifikasi proyek area / modul di mana bug telah diperkenalkan kembali. mulailah dengan proyek-proyek itu untuk menulis tes. Masuk akal untuk menulis tes untuk fungsionalitas baru dan untuk perbaikan bug.

Apakah sepadan dengan upaya untuk solusi yang ada yang ada di produksi?

Iya. Anda akan melihat efek bug turun dan pemeliharaan menjadi lebih mudah

Apakah lebih baik untuk mengabaikan pengujian untuk proyek ini dan menambahkannya dalam kemungkinan menulis ulang di masa depan?

Saya akan merekomendasikan untuk memulai jika dari sekarang.

Apa yang akan lebih bermanfaat; menghabiskan beberapa minggu menambahkan tes atau beberapa minggu menambahkan fungsionalitas?

Anda mengajukan pertanyaan yang salah. Jelas, fungsionalitas lebih penting daripada yang lainnya. Tetapi, Anda sebaiknya bertanya apakah menghabiskan beberapa minggu menambahkan tes akan membuat sistem saya lebih stabil. Apakah ini akan membantu pengguna akhir saya? Apakah ini akan membantu pengembang baru dalam tim untuk memahami proyek dan juga untuk memastikan bahwa dia tidak memperkenalkan bug karena kurangnya pemahaman tentang dampak keseluruhan dari suatu perubahan.

PK
sumber
3

Saya sangat menyukai Refactor the Low-hanging Fruit sebagai jawaban atas pertanyaan dari mana harus memulai refactoring. Ini adalah cara untuk memudahkan ke dalam desain yang lebih baik tanpa menggigit lebih dari yang Anda bisa mengunyah.

Saya pikir logika yang sama berlaku untuk TDD - atau hanya unit test: tulis tes yang Anda butuhkan, saat Anda membutuhkannya; tulis tes untuk kode baru; tulis tes untuk bug saat muncul. Anda khawatir mengabaikan area-area yang lebih sulit dijangkau dari basis kode, dan ini tentu saja berisiko, tetapi sebagai cara untuk memulai: memulai! Anda dapat mengurangi risiko di jalan dengan alat cakupan kode, dan risikonya tidak (menurut saya) sebesar itu: jika Anda menutupi bug, menutupi kode baru, menutupi kode yang Anda lihat , lalu Anda meliput kode yang paling membutuhkan tes.

Carl Manaster
sumber
2
  • ya itu. ketika Anda mulai menambahkan fungsionalitas baru, hal itu dapat menyebabkan beberapa modifikasi kode lama dan sebagai hasilnya merupakan sumber bug potensial.
  • (lihat yang pertama) sebelum Anda mulai menambahkan fungsionalitas baru semua (atau hampir) kode (idealnya) harus dicakup oleh tes unit.
  • (lihat yang pertama dan kedua) :). fungsionalitas muluk yang baru dapat "menghancurkan" kode lama yang bekerja.
garik
sumber
2

Ya itu bisa: Coba saja pastikan semua kode yang Anda tulis mulai sekarang memiliki tes di tempat.

Jika kode yang sudah ada perlu dimodifikasi dan dapat diuji, maka lakukan, tetapi lebih baik jangan terlalu giat dalam mencoba mendapatkan tes untuk kode yang stabil. Hal-hal semacam itu cenderung memiliki efek mengetuk dan dapat lepas kendali.

graham.reeds
sumber
2

Apakah sepadan dengan upaya untuk solusi yang ada yang ada di produksi?
Iya. Tetapi Anda tidak harus menulis semua tes unit untuk memulai. Cukup tambahkan satu per satu.

Apakah lebih baik untuk mengabaikan pengujian untuk proyek ini dan menambahkannya dalam kemungkinan menulis ulang di masa depan?
Tidak. Pertama kali Anda menambahkan kode yang merusak fungsionalitas, Anda akan menyesalinya.

Apa yang akan lebih bermanfaat; menghabiskan beberapa minggu menambahkan tes atau beberapa minggu menambahkan fungsionalitas?
Untuk fungsi baru (kode) itu sederhana. Anda menulis unit test terlebih dahulu dan kemudian fungsionalitasnya. Untuk kode lama Anda memutuskan jalan. Anda tidak harus memiliki semua unit test di tempatnya ... Tambahkan yang paling menyakitkan bagi Anda yang tidak Anda miliki ... Waktu (dan kesalahan) akan menentukan yang mana yang harus Anda fokuskan;)

udo
sumber
2

Memperbarui

6 tahun setelah jawaban asli, saya memiliki pandangan yang sedikit berbeda.

Saya pikir masuk akal untuk menambahkan unit test ke semua kode baru yang Anda tulis - dan kemudian refactor tempat di mana Anda membuat perubahan untuk membuatnya dapat diuji.

Menulis tes sekaligus untuk semua kode Anda yang ada tidak akan membantu - tetapi tidak menulis tes untuk kode baru yang Anda tulis (atau area yang Anda modifikasi) juga tidak masuk akal. Menambahkan tes saat Anda refactor / menambahkan sesuatu mungkin adalah cara terbaik untuk menambahkan tes dan membuat kode lebih mudah dikelola dalam proyek yang sudah ada tanpa tes.

Jawaban sebelumnya

Saya akan mengangkat beberapa alis di sini :)

Pertama-tama apa proyek Anda - jika itu adalah kompiler atau bahasa atau kerangka kerja atau apa pun yang tidak akan berubah secara fungsional untuk waktu yang lama, maka saya pikir itu benar-benar fantastis untuk menambahkan tes unit.

Namun, jika Anda bekerja pada aplikasi yang mungkin akan memerlukan perubahan fungsionalitas (karena perubahan persyaratan) maka tidak ada gunanya mengambil upaya ekstra itu.

Mengapa?

  1. Tes unit hanya mencakup tes kode - apakah kode melakukan apa yang dirancang untuk - itu bukan pengganti untuk pengujian manual yang harus dilakukan (untuk mengungkap bug fungsional, masalah kegunaan dan semua jenis masalah lainnya)

  2. Tes unit membutuhkan waktu! Sekarang dari mana saya berasal, itu adalah komoditas berharga - dan bisnis umumnya memilih fungsionalitas yang lebih baik daripada test suite lengkap.

  3. Jika aplikasi Anda bahkan sangat berguna bagi pengguna, mereka akan meminta perubahan - jadi Anda akan memiliki versi yang akan melakukan hal-hal yang lebih baik, lebih cepat dan mungkin melakukan hal-hal baru - mungkin juga ada banyak refactoring saat kode Anda bertambah. Mempertahankan unit test unit dewasa dalam lingkungan yang dinamis adalah sakit kepala.

  4. Tes unit tidak akan mempengaruhi persepsi kualitas produk Anda - kualitas yang dilihat pengguna. Tentu, metode Anda mungkin bekerja persis seperti yang mereka lakukan pada hari 1, antarmuka antara lapisan presentasi dan lapisan bisnis mungkin murni - tapi coba tebak? Pengguna tidak peduli! Dapatkan beberapa penguji nyata untuk menguji aplikasi Anda. Dan lebih sering daripada tidak, metode dan antarmuka tersebut harus berubah, cepat atau lambat.

Apa yang akan lebih bermanfaat; menghabiskan beberapa minggu menambahkan tes atau beberapa minggu menambahkan fungsionalitas? - Ada banyak hal yang dapat Anda lakukan lebih baik daripada menulis tes - Menulis fungsionalitas baru, meningkatkan kinerja, meningkatkan kegunaan, menulis manual bantuan yang lebih baik, menyelesaikan bug yang tertunda, dll.

Sekarang jangan salah paham - Jika Anda benar-benar yakin bahwa segala sesuatu tidak akan berubah selama 100 tahun ke depan, silakan, jatuhkan diri Anda dan tulis tes-tes itu. Tes Otomatis adalah ide bagus untuk API juga, di mana Anda sama sekali tidak ingin memecah kode pihak ketiga. Di tempat lain, itu hanya sesuatu yang membuat saya mengirim nanti!

Roopesh Shenoy
sumber
Dan saya mendorong Anda untuk membaca ini - joelonsoftware.com/items/2009/01/31.html
Roopesh Shenoy
Apakah Anda lebih suka 'memperbaiki bug yang tertunda' atau mencegahnya muncul? Pengujian unit yang tepat menghemat waktu dengan meminimalkan jumlah waktu yang dihabiskan untuk memperbaiki bug.
Ihor Kaharlichenko
Itu hanya mitos. Jika Anda memberi tahu saya bahwa pengujian unit otomatis adalah pengganti untuk pengujian manual, maka Anda benar-benar keliru. Dan apa yang dicatat oleh penguji manual, jika bukan bug?
Roopesh Shenoy
Dan ya jangan salah paham - Saya tidak mengatakan unit test adalah pemborosan mutlak - intinya adalah mempertimbangkan waktu yang diperlukan untuk menuliskannya dan alasan mengapa mereka harus berubah ketika Anda mengganti produk Anda, apakah mereka benar-benar membayar kembali. Bagi saya, saya telah mencoba kedua belah pihak dan jawabannya adalah tidak, mereka tidak membayar cukup cepat.
Roopesh Shenoy
1

Kemungkinan Anda tidak akan pernah memiliki cakupan tes yang signifikan, jadi Anda harus taktis tentang tempat Anda menambahkan tes:

  • Seperti yang Anda sebutkan, ketika Anda menemukan bug, ini saat yang tepat untuk menulis tes (untuk mereproduksinya), dan kemudian memperbaiki bug. Jika Anda melihat tes mereproduksi bug, Anda dapat yakin itu adalah tes alid yang bagus. Mengingat sebagian besar bug adalah regresi (50%?), Hampir selalu layak untuk menulis tes regresi.
  • Saat Anda menyelami area kode untuk memodifikasinya, ini saat yang tepat untuk menulis tes di sekitarnya. Bergantung pada sifat kodenya, tes yang berbeda sesuai. Satu set saran yang bagus dapat ditemukan di sini .

OTOH, tidak layak hanya duduk-duduk menulis tes di sekitar kode yang orang senang dengan - terutama jika tidak ada yang akan memodifikasinya. Itu hanya tidak menambah nilai (kecuali mungkin memahami perilaku sistem).

Semoga berhasil!

ndp
sumber
1

Jika saya berada di tempat Anda, saya mungkin akan mengambil pendekatan luar-dalam, dimulai dengan tes fungsional yang melatih seluruh sistem. Saya akan mencoba mendokumentasikan ulang persyaratan sistem menggunakan bahasa spesifikasi BDD seperti RSpec, dan kemudian menulis tes untuk memverifikasi persyaratan tersebut dengan mengotomatiskan antarmuka pengguna.

Kemudian saya akan melakukan pengembangan didorong cacat untuk bug yang baru ditemukan, menulis tes unit untuk mereproduksi masalah, dan bekerja pada bug sampai tes lulus.

Untuk fitur-fitur baru, saya akan tetap menggunakan pendekatan luar-dalam: Mulai dengan fitur-fitur yang didokumentasikan dalam RSpec dan diverifikasi dengan mengotomatiskan antarmuka pengguna (yang tentu saja akan gagal pada awalnya), kemudian menambahkan tes unit yang lebih berbutir halus saat implementasi berjalan.

Saya bukan ahli dalam prosesnya, tetapi dari sedikit pengalaman yang saya miliki, saya dapat memberi tahu Anda bahwa BDD melalui pengujian UI otomatis tidak mudah, tetapi saya pikir itu sepadan dengan usaha, dan mungkin akan menghasilkan manfaat paling besar dalam kasus Anda.

Mhmmd
sumber
1

Saya bukan ahli TDD berpengalaman dengan cara apa pun, tapi tentu saja saya akan mengatakan bahwa itu sangat penting untuk unit test sebanyak yang Anda bisa. Karena kode sudah ada di tempat, saya akan mulai dengan mendapatkan semacam otomatisasi unit test di tempat. Saya menggunakan TeamCity untuk melakukan semua tes dalam proyek saya, dan itu memberi Anda ringkasan yang bagus tentang bagaimana komponen melakukannya.

Dengan itu, saya akan beralih ke komponen logika bisnis yang sangat kritis yang tidak dapat gagal. Dalam kasus saya, ada beberapa masalah trigometri dasar yang perlu diselesaikan untuk berbagai input, jadi saya menguji coba itu. Alasan saya melakukan ini adalah ketika saya membakar minyak tengah malam, sangat mudah untuk membuang waktu menggali ke kedalaman kode yang benar-benar tidak perlu disentuh, karena Anda tahu mereka diuji untuk semua input yang mungkin (dalam kasus saya, ada sejumlah input terbatas).

Ok, jadi sekarang Anda mudah-mudahan merasa lebih baik tentang potongan-potongan penting. Alih-alih duduk dan melakukan semua tes, saya akan menyerang mereka saat mereka muncul. Jika Anda menabrak bug yang merupakan PITA nyata untuk diperbaiki, tulis unit test untuk itu dan keluarkan.

Ada kasus di mana Anda akan menemukan bahwa pengujian itu sulit karena Anda tidak dapat membuat instance kelas tertentu dari tes, jadi Anda harus mengejeknya. Oh, tapi mungkin Anda tidak bisa mengejeknya dengan mudah karena Anda tidak menulis ke antarmuka. Saya mengambil skenario "whoops" ini sebagai kesempatan untuk mengimplementasikan antarmuka tersebut, karena, yah, ini adalah Good Thing.

Dari sana, saya akan membuat server build Anda atau otomatisasi apa pun yang Anda miliki dikonfigurasi dengan alat cakupan kode. Mereka membuat grafik batang yang buruk dengan zona merah besar di mana Anda memiliki jangkauan yang buruk. Sekarang cakupan 100% bukan tujuan Anda, juga cakupan 100% tidak berarti bahwa kode Anda anti peluru, tetapi bilah merah pasti memotivasi saya ketika saya memiliki waktu luang. :)

Dave
sumber
1

Ada begitu banyak jawaban yang baik sehingga saya tidak akan mengulangi isinya. Saya memeriksa profil Anda dan sepertinya Anda adalah pengembang C # .NET. Karena itu saya menambahkan referensi ke proyek Microsoft PEX dan Moles yang dapat membantu Anda dengan autogenerating unit test untuk kode lawas. Saya tahu bahwa autogenerasi bukanlah cara terbaik tetapi setidaknya itu adalah cara untuk memulai. Lihat artikel yang sangat menarik ini dari majalah MSDN tentang penggunaan PEX untuk kode lawas .

Ladislav Mrnka
sumber
1

Saya sarankan untuk membaca artikel yang brilian oleh TopTal Engineer, yang menjelaskan di mana harus mulai menambahkan tes: itu berisi banyak matematika, tetapi ide dasarnya adalah:

1) Ukur kode Afferent Coupling (CA) kode Anda (seberapa banyak kelas digunakan oleh kelas lain, artinya memecahnya akan menyebabkan kerusakan luas)

2) Ukur Kompleksitas Siklomik (CC) kode Anda (kompleksitas lebih tinggi = perubahan pemutusan yang lebih tinggi)

Anda perlu mengidentifikasi kelas dengan CA dan CC tinggi, yaitu memiliki fungsi f (CA, CC) dan kelas dengan perbedaan terkecil antara dua metrik harus diberi prioritas tertinggi untuk cakupan pengujian.

Mengapa? Karena CA tinggi tetapi kelas CC sangat rendah sangat penting tetapi tidak mungkin rusak. Di sisi lain, CA rendah tetapi CC tinggi cenderung rusak, tetapi akan menyebabkan lebih sedikit kerusakan. Jadi, Anda ingin menyeimbangkan.

Andrejs
sumber
0

Tergantung ...
Sangat menyenangkan untuk memiliki unit test tetapi Anda perlu mempertimbangkan siapa pengguna Anda dan apa yang bersedia mereka toleransi untuk mendapatkan produk yang lebih bebas bug. Tidak dapat dihindari dengan refactoring kode Anda yang tidak memiliki unit test saat ini, Anda akan memperkenalkan bug dan banyak pengguna akan merasa sulit untuk memahami bahwa Anda membuat produk sementara lebih rusak untuk membuatnya kurang rusak dalam jangka panjang. Pada akhirnya itu adalah pengguna yang akan memiliki keputusan akhir ...

trendl
sumber
-2

Iya. Tidak. Menambahkan tes.

Menuju pendekatan yang lebih TDD sebenarnya akan lebih baik menginformasikan upaya Anda untuk menambahkan fungsionalitas baru dan membuat pengujian regresi jauh lebih mudah. Saksikan berikut ini!

indera
sumber