Jawaban:
Bagaimana tes Anda disusun agak tidak penting dibandingkan dengan pentingnya memiliki semuanya.
Hal yang paling penting untuk rangkaian uji yang baik adalah ia mencakup semua fungsi; yang memastikan bahwa setiap kali cacat regresi diperkenalkan, Anda akan segera melihat. Apakah menulis satu tes untuk setiap metode, satu tes untuk setiap kombinasi nilai input dari suatu metode, atau bahkan satu tes untuk setiap jalur kode yang mungkin dalam metode itu kurang penting. Apakah mengorganisasi tes-tes ini menjadi beberapa atau beberapa kelas tes bahkan kurang penting: suatu test suite harus selalu berhasil secara penuh, jadi tidak masalah apakah itu gagal satu dari tiga atau dua dari tujuh belas tes - keduanya salah dan harus tetap.
Tentu saja, kode tes juga merupakan kode, sehingga harus mengikuti praktik terbaik normal untuk dapat dipelihara, modular, dll. Tetapi itu harus diputuskan dengan seberapa baik perawatan suite uji itu sendiri, bukan dengan bagaimana kelas tes berhubungan dengan kelas yang mereka uji. Kedua kebijakan yang Anda sebutkan dapat membantu Anda mengingat di mana menemukan sesuatu jika Anda mengikutinya secara konsisten, tetapi untuk itu konsistensi lebih penting daripada pilihan kebijakan.
Untuk pertanyaan spesifik Anda, konvensi JUnit, adalah memiliki korespondensi 1: 1 antara kelas aplikasi Anda ( Foo1.java
, Foo2.java
) dan kelas uji JUnit ( Foo1Test.java
, Foo2Test.java
).
Yang mengatakan, saya setuju dengan sepenuh hati dengan Kilian menyoroti pentingnya semangat / tujuan pengujian unit atas skema organisasi apa pun yang mungkin digunakan. Pilih beberapa konvensi dan ikuti sebagian besar waktu, sambil dengan hati-hati mengizinkan pengecualian untuk konvensi Anda, ketika mereka dibenarkan.
Apakah lebih baik memiliki kelas terpisah untuk setiap metode, atau hanya memiliki satu kelas uji untuk setiap kelas aktual?
Jika Anda perlu menulis kelas tes terpisah untuk metode satu kelas, maka Anda memiliki desain yang salah. Metode harus kecil, mudah dibaca, mudah diuji dan mudah diubah. Tes bisa sedikit lebih lama daripada kode asli karena membuat testdata, mengejek dll, tetapi tidak boleh secara signifikan lebih lama. Jika ya, kelas Anda yang diuji terlalu rumit dan pasti lebih dari satu hal ( prinsip tanggung jawab tunggal ): Kerjakan desain Anda.
Saya pikir "satu kelas uji per metode" dan "satu kelas uji per kelas" biasanya terlalu ekstrem.
Secara umum, Anda ingin memiliki satu pemeriksaan per metode pengujian / unit test. Misalnya, ini bisa berupa beberapa pernyataan untuk memeriksa bahwa list.isEmpty = true
dan list.Length = 0
, jadi satu metode uji / uji unit per perilaku.
Ini membuatnya mudah untuk menghasilkan nama metode pengujian yang menggambarkan perilaku. Anda ingin mengelompokkan metode pengujian dalam kelas tes, jadi ketika Anda membaca test classname.test method
, itu masuk akal. Biasanya, mereka memiliki beberapa kode pengaturan bersama yang kemudian mudah dimasukkan ke dalam pengaturan / fixture tes. Tergantung pada kelas yang diuji, ini bisa menjadi satu kelas tes untuk seluruh kelas, dan itu juga bisa menjadi satu kelas tes untuk satu metode. Tapi biasanya, itu akan berada di antara keduanya.
Seperti halnya kode normal, Anda ingin agar tes dapat dibaca sebanyak mungkin. Apa yang membantu saya adalah mengikuti gaya BDD yang diberikan ketika-saat-saat atau mengatur-bertindak-tegas mengatur kode tes. Sebuah kelas tes bisa memberikannya, itu pengaturan. Kemudian, setiap metode pengujian di kelas itu menggunakan yang diberikan (atau bagian dari itu) dan memiliki satu kapan dan satu kemudian.
Pikirkan juga tes unit sebagai dokumentasi tentang cara menggunakan fungsionalitas kelas yang diuji. Dengan tes unit yang baik, Anda dapat membaca tes untuk mengetahui cara menggunakan fungsionalitas kelas yang ingin Anda gunakan, dan apa efeknya sebenarnya.
Ketika sesuatu rusak dan tes unit gagal, Anda ingin semudah mungkin untuk memahami apa yang rusak, satu pernyataan per tes sangat membantu di sini. Ketika ada beberapa pernyataan dalam satu tes, hanya yang pertama gagal dan kemudian metode keluar, jadi Anda tidak tahu apakah perilaku lain yang diuji dalam tes berikut ini juga rusak sampai Anda memperbaiki hal yang membuat pernyataan pertama gagal. Dengan satu pernyataan, semua metode pengujian Anda yang lain masih bisa dieksekusi dan jauh lebih cepat untuk memahami kedalaman kegagalan.
Tentu saja, saya setuju dengan Kilian Foth: dalam praktiknya, Anda bisa beruntung memiliki beberapa unit test untuk kode yang sedang Anda kerjakan. Dan setiap tes kecil yang dilokalkan lebih baik daripada tidak ada tes sama sekali, atau hanya tes integrasi besar yang berjalan di server build yang menghabiskan banyak waktu dan biasanya tidak terlalu terlokalisasi (mereka tidak memberi tahu Anda dengan cepat di mana kesalahannya - Anda harus bekerja sedikit).
Saya pikir itu benar bahwa setiap kelas memiliki kelas ujiannya. Idenya adalah memusatkan semua tes unit yang terkait dengan kelas target dalam satu kelas tes. Maka, misalnya, MyClass.java
akan memiliki kelas tes yang disebut MyClassTest.java
.