Saya menguji-mengemudi metode yang menghasilkan kumpulan objek data. Saya ingin memverifikasi bahwa properti objek sedang diatur dengan benar. Beberapa properti akan diatur ke hal yang sama; yang lain akan ditetapkan ke nilai yang tergantung pada posisi mereka dalam koleksi. Cara alami untuk melakukan ini tampaknya dengan loop. Namun, Roy Osherove sangat menyarankan untuk tidak menggunakan logika dalam unit test ( Art of Unit Testing , 178). Dia berkata:
Tes yang berisi logika biasanya menguji lebih dari satu hal pada suatu waktu, yang tidak disarankan, karena tes tersebut kurang mudah dibaca dan lebih rapuh. Tetapi test logic juga menambah kompleksitas yang mungkin mengandung bug tersembunyi.
Pengujian harus, sebagai aturan umum, menjadi serangkaian panggilan metode tanpa aliran kontrol, bahkan
try-catch
, dan dengan panggilan tegas.
Namun, saya tidak dapat melihat ada yang salah dengan desain saya (bagaimana lagi Anda menghasilkan daftar objek data, beberapa yang nilainya bergantung pada di mana dalam urutannya? —Tidak dapat menghasilkan dan mengujinya secara terpisah). Apakah ada sesuatu yang tidak ramah uji dengan desain saya? Atau apakah saya terlalu setia pada pengajaran Osherove? Atau adakah sihir tes unit rahasia yang saya tidak tahu tentang hal itu menghindari masalah ini? (Saya menulis dalam bahasa C # / VS2010 / NUnit, tetapi mencari jawaban agnostik bahasa jika memungkinkan.)
sumber
in
) diperlukan, jika pengujiannya "Frob berhasil ditambahkan ke koleksi yang ada".toString()
Koleksi dan membandingkan dengan apa yang seharusnya. Sederhana dan berhasil.Jawaban:
TL; DR:
Hal pertama untuk pengujian adalah tentang dogma yang tidak membantu. Saya menikmati membaca The Way of Testivus yang menunjukkan beberapa masalah dengan dogma dengan cara yang ringan.
Jika tes perlu ditulis dengan cara tertentu, tulis seperti itu. Mencoba memaksa tes ke beberapa tata letak tes ideal atau tidak memilikinya sama sekali bukan hal yang baik. Memiliki tes hari ini yang menguji itu lebih baik daripada memiliki tes "sempurna" beberapa hari kemudian.
Saya juga akan menunjukkan bit pada tes jelek:
Ini dapat dianggap disangkal bagi mereka yang telah mengikuti untuk waktu yang lama ... dan mereka menjadi tertanam dalam cara berpikir dan menulis tes. Bagi orang-orang yang belum dan sedang berusaha untuk sampai ke titik itu, pengingat dapat membantu (saya bahkan menemukan membaca ulang mereka membantu saya menghindari terkunci ke dalam dogma).
Pertimbangkan bahwa ketika menulis tes jelek, jika kode itu mungkin merupakan indikasi bahwa kode tersebut mencoba melakukan terlalu banyak. Jika kode yang Anda uji terlalu rumit untuk dapat dilakukan dengan baik dengan menulis tes sederhana, Anda mungkin ingin mempertimbangkan untuk memecah kode menjadi bagian-bagian yang lebih kecil yang dapat diuji dengan tes yang lebih sederhana. Seseorang seharusnya tidak menulis tes unit yang melakukan segalanya (itu mungkin bukan tes unit ). Sama seperti 'objek dewa' buruk, 'tes unit dewa' juga buruk dan harus menjadi indikasi untuk kembali dan melihat kode lagi.
Anda harus dapat menggunakan semua kode dengan cakupan yang masuk akal melalui tes sederhana tersebut. Tes yang melakukan lebih banyak ujung ke ujung pengujian yang berhubungan dengan pertanyaan yang lebih besar ("Saya memiliki objek ini, disusun ke xml, dikirim ke layanan web, melalui aturan, mundur, dan tidak tertandai") adalah tes yang sangat baik - tetapi tentu saja tidak adalah unit test (dan jatuh ke ranah pengujian integrasi - bahkan jika ia telah mengolok-olok layanan yang ia panggil dan kustom dalam database memori untuk melakukan pengujian). Mungkin masih menggunakan kerangka kerja XUnit untuk pengujian, tetapi kerangka kerja pengujian tidak membuatnya menjadi unit test.
sumber
Saya menambahkan jawaban baru karena sudut pandang saya berbeda dari ketika saya menulis pertanyaan dan jawaban yang asli; tidak masuk akal untuk menyatukan mereka menjadi satu.
Saya katakan dalam pertanyaan awal
Di sinilah saya salah. Setelah melakukan pemrograman fungsional untuk tahun lalu, saya sekarang menyadari bahwa saya hanya perlu operasi pengumpulan dengan akumulator. Kemudian saya bisa menulis fungsi saya sebagai fungsi murni yang beroperasi pada satu hal dan menggunakan beberapa fungsi perpustakaan standar untuk menerapkannya ke koleksi.
Jadi jawaban baru saya adalah: gunakan teknik pemrograman fungsional dan Anda akan menghindari masalah ini hampir sepanjang waktu. Anda dapat menulis fungsi Anda untuk beroperasi pada satu hal dan hanya menerapkannya pada koleksi hal pada saat terakhir. Tetapi jika mereka murni, Anda dapat mengujinya tanpa referensi koleksi.
Untuk logika yang lebih kompleks, bersandar pada tes berbasis properti . Ketika mereka memiliki logika, itu harus kurang dari dan terbalik dengan logika kode yang diuji, dan setiap tes memverifikasi jauh lebih banyak daripada uji unit berbasis kasus bahwa jumlah kecil logika sepadan.
Di atas semua selalu bersandar pada tipenya . Dapatkan tipe terkuat yang Anda bisa dan gunakan untuk keuntungan Anda. Ini akan mengurangi jumlah tes yang harus Anda tulis di tempat pertama.
sumber
Jangan mencoba menguji terlalu banyak hal sekaligus. Setiap properti dari setiap objek data dalam koleksi terlalu banyak untuk satu tes. Sebagai gantinya, saya merekomendasikan:
Melakukannya dengan cara ini membuat tes cukup kecil sehingga meninggalkan loop tidak terasa menyakitkan. Contoh C # / Unit, diberikan metode yang sedang diuji
ICollection<Foo> generateFoos(uint numberOfFoos)
:Jika Anda terbiasa dengan paradigma "flat unit test" (tidak ada struktur / logika bersarang), tes ini tampaknya cukup bersih. Dengan demikian logika dihindari dalam pengujian dengan mengidentifikasi masalah asli sebagai mencoba menguji terlalu banyak properti sekaligus, daripada kekurangan loop.
sumber