Kami telah menulis hampir 3.000 tes - data telah dikodekan dengan keras, sangat sedikit penggunaan kembali kode. Metodologi ini sudah mulai menggigit kita. Saat sistem berubah, kami mendapati diri kami menghabiskan lebih banyak waktu memperbaiki tes yang rusak. Kami memiliki tes unit, integrasi dan fungsional.
Apa yang saya cari adalah cara yang pasti untuk menulis tes yang dapat dikelola dan dikelola.
Kerangka kerja
.net
unit-testing
Chuck Conway
sumber
sumber
Jawaban:
Jangan menganggapnya sebagai "tes unit rusak", karena tidak.
Itu adalah spesifikasi, yang tidak lagi didukung oleh program Anda.
Jangan menganggapnya sebagai "memperbaiki tes", tetapi sebagai "mendefinisikan persyaratan baru".
Tes harus menentukan aplikasi Anda terlebih dahulu, bukan sebaliknya.
Anda tidak bisa mengatakan Anda memiliki implementasi yang berfungsi sampai Anda tahu itu berhasil. Anda tidak bisa mengatakan itu berfungsi sampai Anda mengujinya.
Beberapa catatan lain yang mungkin memandu Anda:
sumber
Don't think of it as "fixing the tests", but as "defining new requirements".
Apa yang Anda gambarkan mungkin sebenarnya bukan hal yang buruk, tetapi petunjuk untuk masalah yang lebih dalam yang ditemukan oleh tes Anda
Jika Anda dapat mengubah kode Anda, dan tes Anda tidak akan pecah, itu akan mencurigakan bagi saya. Perbedaan antara perubahan yang sah dan bug hanya fakta bahwa itu diminta, apa yang diminta (diasumsikan TDD) ditentukan oleh pengujian Anda.
Data kode yang sulit dalam tes adalah hal yang baik. Tes berfungsi sebagai pemalsuan, bukan sebagai bukti. Jika terlalu banyak perhitungan, tes Anda mungkin berupa tautologi. Sebagai contoh:
Semakin tinggi abstraksi, semakin dekat Anda dengan algoritma, dan dengan itu, semakin dekat untuk membandingkan implementasi acutal dengan dirinya sendiri.
Penggunaan kembali kode yang terbaik dalam tes adalah imho 'Cek', seperti pada jUnits
assertThat
, karena mereka menjaga tes sederhana. Selain itu, jika pengujian dapat dilakukan refactored untuk membagikan kode, kode sebenarnya yang diuji kemungkinan juga bisa , sehingga mengurangi tes menjadi tes yang menguji basis refactored.sumber
Saya juga punya masalah ini. Pendekatan saya yang lebih baik adalah sebagai berikut:
Jangan menulis unit test kecuali itu satu-satunya cara yang baik untuk menguji sesuatu.
Saya sepenuhnya siap untuk mengakui bahwa unit test memiliki biaya diagnosis dan waktu perbaikan terendah. Ini membuat mereka alat yang berharga. Masalahnya adalah, dengan jarak tempuh Anda yang jelas-mungkin-bervariasi, bahwa tes unit seringkali terlalu kecil untuk pantas biaya mempertahankan massa kode. Saya menulis contoh di bagian bawah, lihatlah.
Gunakan pernyataan di mana pun mereka setara dengan tes unit untuk komponen itu. Pernyataan memiliki properti bagus yang selalu diverifikasi di seluruh debug build. Jadi, alih-alih menguji batasan kelas "Karyawan" di unit tes terpisah, Anda secara efektif menguji kelas Karyawan melalui setiap kasus uji dalam sistem. Pernyataan juga memiliki properti bagus yang tidak menambah massa kode sebanyak tes unit (yang akhirnya membutuhkan perancah / mengejek / apa pun).
Sebelum seseorang membunuh saya: produksi tidak boleh macet karena asersi. Sebagai gantinya, mereka harus masuk pada level "Kesalahan".
Sebagai peringatan bagi seseorang yang belum memikirkannya, jangan nyatakan apa pun tentang input pengguna atau jaringan. Ini adalah kesalahan besar ™.
Di basis kode terbaru saya, saya telah dengan bijaksana menghapus unit test di mana pun saya melihat peluang yang jelas untuk pernyataan. Ini secara signifikan menurunkan biaya perawatan secara keseluruhan dan membuat saya menjadi orang yang jauh lebih bahagia.
Pilih pengujian sistem / integrasi, implementasikan untuk semua aliran utama dan pengalaman pengguna Anda. Kasus sudut mungkin tidak perlu ada di sini. Tes sistem memverifikasi perilaku di sisi pengguna dengan menjalankan semua komponen. Karena itu, tes sistem tentu lebih lambat, jadi tulis yang penting (tidak lebih, tidak kurang) dan Anda akan menangkap masalah yang paling penting. Tes sistem memiliki overhead perawatan yang sangat rendah.
Penting untuk diingat bahwa, karena Anda menggunakan pernyataan, setiap pengujian sistem akan menjalankan beberapa ratus "unit test" secara bersamaan. Anda juga agak yakin bahwa yang paling penting dijalankan berulang kali.
Tulis API yang kuat yang dapat diuji secara fungsional. Tes fungsional canggung dan (mari kita hadapi) agak tidak berarti jika API Anda membuatnya terlalu sulit untuk memverifikasi komponen yang berfungsi sendiri. Desain API yang baik a) membuat langkah-langkah pengujian menjadi mudah dan b) menghasilkan pernyataan yang jelas dan berharga.
Pengujian fungsional adalah hal yang paling sulit untuk dilakukan dengan benar, terutama ketika Anda memiliki komponen yang berkomunikasi satu-ke-banyak atau (bahkan lebih buruk, oh tuhan) banyak-ke-banyak di seluruh hambatan proses. Semakin banyak input dan output yang terpasang pada satu komponen, semakin sulit pengujian fungsionalnya, karena Anda harus mengisolasi salah satunya untuk benar-benar menguji fungsionalitasnya.
Pada masalah "jangan tulis unit test," saya akan memberikan contoh:
Penulis tes ini telah menambahkan tujuh baris yang tidak berkontribusi sama sekali pada verifikasi produk akhir. Pengguna seharusnya tidak pernah melihat hal ini terjadi, baik karena a) tidak seorang pun boleh lewat NULL di sana (jadi tuliskan pernyataan), lalu) atau b) kasing NULL harus menyebabkan beberapa perilaku yang berbeda. Jika case (b), tulis tes yang benar-benar memverifikasi perilaku itu.
Filosofi saya adalah bahwa kita tidak boleh menguji artefak implementasi. Kami hanya harus menguji apa pun yang dapat dianggap sebagai hasil aktual. Kalau tidak, tidak ada cara untuk menghindari penulisan dua kali massa dasar kode antara tes unit (yang memaksa implementasi tertentu) dan implementasi itu sendiri.
Penting untuk dicatat, di sini, bahwa ada kandidat yang baik untuk tes unit. Bahkan, bahkan ada beberapa situasi di mana tes unit adalah satu-satunya cara yang memadai untuk memverifikasi sesuatu dan di mana itu bernilai tinggi untuk menulis dan mempertahankan tes tersebut. Dari bagian atas kepala saya, daftar ini termasuk algoritma nontrivial, wadah data yang terbuka di API, dan kode yang sangat dioptimalkan yang muncul "rumit" (alias "orang berikutnya mungkin akan mengacaukannya.").
Saran khusus saya kepada Anda, maka: Mulai hapus pengujian unit secara bijaksana saat mereka rusak, tanyakan pada diri Anda pertanyaan, "apakah ini output, atau saya membuang-buang kode?" Anda mungkin akan berhasil mengurangi jumlah hal yang menghabiskan waktu Anda.
sumber
Sepertinya pengujian unit Anda bekerja seperti pesona. Ini adalah yang baik hal yang begitu rapuh untuk perubahan, karena itu semacam seluruh titik. Perubahan kecil dalam tes pemutusan kode sehingga Anda dapat menghilangkan kemungkinan kesalahan di seluruh program Anda.
Namun, perlu diingat bahwa Anda hanya benar-benar perlu menguji kondisi yang akan membuat metode Anda gagal atau memberikan hasil yang tidak terduga. Ini akan membuat pengujian unit Anda lebih rentan untuk "pecah" jika ada masalah asli daripada hal-hal sepele.
Meskipun menurut saya Anda sangat mendesain ulang program. Dalam hal ini, lakukan apa pun yang Anda perlukan dan hapus tes lama dan ganti dengan yang baru sesudahnya. Perbaikan unit test hanya bermanfaat jika Anda tidak memperbaikinya karena perubahan radikal dalam program Anda. Kalau tidak, Anda mungkin mendapati bahwa Anda mendedikasikan terlalu banyak waktu untuk menulis ulang tes agar dapat diterapkan di bagian kode program yang baru Anda tulis.
sumber
Saya yakin orang lain akan memiliki banyak masukan, tetapi dalam pengalaman saya, ini adalah beberapa hal penting yang akan membantu Anda:
sumber
Tangani tes seperti Anda melakukannya dengan kode sumber.
Kontrol versi, rilis pos pemeriksaan, pelacakan masalah, "kepemilikan fitur", estimasi perencanaan dan upaya, dll. Pernahkah ada yang melakukannya - Saya pikir ini adalah cara paling efisien untuk menangani masalah seperti yang Anda jelaskan.
sumber
Anda pasti harus melihat pola tes XUnit Gerard Meszaros . Ini memiliki bagian yang hebat dengan banyak resep untuk menggunakan kembali kode tes Anda dan menghindari duplikasi.
Jika tes Anda rapuh, bisa juga Anda tidak cukup menggunakan tes ganda. Terutama, jika Anda membuat kembali seluruh grafik objek pada awal setiap unit test, bagian Arrange dalam tes Anda mungkin menjadi terlalu besar dan Anda mungkin sering menemukan diri Anda dalam situasi di mana Anda harus menulis ulang bagian Arrange dalam sejumlah besar tes hanya karena salah satu kelas yang paling sering Anda gunakan telah berubah. Mengolok-olok dan bertopik dapat membantu Anda di sini dengan mengurangi jumlah objek yang Anda harus rehydrate untuk memiliki konteks pengujian yang relevan.
Mengambil detail yang tidak penting dari pengaturan pengujian Anda melalui mengejek dan bertopik dan menerapkan pola pengujian untuk menggunakan kembali kode harus mengurangi kerapuhan mereka secara signifikan.
sumber