Apakah lebih baik memiliki a
- Rangkaian tes deterministik, yang menghasilkan tes yang sama berhasil
- Rangkaian uji non-deterministik, yang berpotensi mencakup lebih banyak kasus
?
Contoh: Anda menulis rangkaian uji untuk menguji fungsionalitas pengontrol di aplikasi MVC. Pengontrol membutuhkan data aplikasi dari database sebagai input selama pengujian. Ada dua opsi untuk melakukan ini:
- Anda menyandikan baris mana dari database tes yang dipilih sebagai input (mis. Baris ke-10 dan ke-4)
- Anda menggunakan generator nomor acak untuk secara acak mengambil data dari database (dua baris dipilih oleh generator nomor acak)
Yang pertama adalah deterministik: setiap uji untuk revisi kode yang sama harus menghasilkan hasil yang sama. Yang kedua adalah non-deterministik: setiap rangkaian test suite memiliki kemungkinan untuk menghasilkan hasil yang berbeda. Namun data yang dipilih secara acak mungkin merupakan representasi yang lebih baik dari kasus tepi data. Mungkin mensimulasikan pengguna yang memberi makan pengontrol kami dengan data yang tidak dapat diprediksi lebih baik?
Apa alasan untuk memilih satu dari yang lain?
Jawaban:
Ketika setiap rangkaian test suite memberi Anda kemungkinan untuk menghasilkan hasil yang berbeda, tes ini hampir sama sekali tidak berharga - ketika suite menunjukkan Anda bug, Anda memiliki kemungkinan besar bahwa Anda tidak dapat mereproduksinya, dan ketika Anda mencoba untuk memperbaiki bug, Anda tidak dapat memverifikasi apakah perbaikan Anda berhasil.
Jadi ketika Anda berpikir Anda perlu menggunakan semacam generator angka acak untuk menghasilkan data pengujian Anda, pastikan Anda selalu menginisialisasi generator dengan seed yang sama, atau bertahan data uji acak Anda dalam file sebelum memasukkannya ke dalam tes Anda, sehingga Anda dapat menjalankan kembali pengujian dengan tepat dengan data yang sama dari proses sebelumnya. Dengan cara ini, Anda dapat mengubah tes non-deterministik menjadi tes deterministik.
EDIT: Menggunakan generator angka acak untuk mengambil beberapa data uji adalah IMHO kadang-kadang pertanda terlalu malas memilih data uji yang bagus . Alih-alih melemparkan 100.000 nilai tes yang dipilih secara acak dan berharap bahwa ini akan cukup untuk menemukan semua bug serius secara kebetulan, lebih baik gunakan otak Anda, pilih 10 hingga 20 kasus "menarik", dan gunakan untuk test suite. Ini tidak hanya menghasilkan kualitas tes yang lebih baik, tetapi juga kinerja suite yang jauh lebih tinggi.
sumber
Baik deterministik dan non-deterministik memiliki tempat
Saya akan membaginya sebagai berikut:
Tes unit.
Ini harus memiliki tes deterministik, berulang dengan data yang sama persis setiap waktu. Tes unit menyertai bagian kode yang spesifik dan terisolasi dan harus mengujinya secara deterministik.
Tes stres fungsional dan input.
Ini dapat menggunakan pendekatan non-deterministik dengan peringatan berikut:
sumber
Kedua.
Tes deterministik dan nondeterministik memiliki berbagai kasus penggunaan dan nilai yang berbeda untuk paket Anda. Umumnya nondeterministic tidak dapat memberikan presisi yang sama dengan pengujian deterministik, yang perlahan-lahan tumbuh menjadi "pengujian nondeterministic tidak memberikan nilai." Ini salah. Mereka mungkin kurang tepat, tetapi mereka juga bisa jauh lebih luas, yang memiliki manfaatnya sendiri.
Mari kita ambil contoh: Anda menulis fungsi yang mengurutkan daftar bilangan bulat. Apa yang akan menjadi beberapa tes unit deterministik yang menurut Anda berguna?
NaN
,INT_MIN
, danINT_MAX
Dan itu hanya fungsi penyortiran! Tentu, Anda dapat berargumen bahwa beberapa di antaranya tidak perlu, atau beberapa di antaranya dapat dikesampingkan dengan alasan informal. Tapi kami insinyur dan kami melihat alasan informal meledak di wajah kami. Kami tahu kami tidak cukup pintar untuk sepenuhnya memahami sistem yang kami bangun atau sepenuhnya menyimpan kompleksitas di kepala kami. Itu sebabnya kami menulis tes di tempat pertama. Menambahkan pengujian nondeterministik hanya mengatakan bahwa kita mungkin tidak harus cukup pintar untuk mengetahui semua tes yang baik secara apriori. Dengan melemparkan data semi-acak ke dalam fungsi Anda, Anda akan lebih mungkin menemukan casing tepi yang Anda lewatkan.
Tentu saja, itu tidak mengesampingkan pengujian deterministik. Pengujian nondeterministic membantu menemukan bug di petak besar program. Namun, begitu Anda menemukan bug, Anda membutuhkan cara yang dapat direproduksi untuk menunjukkan bahwa Anda telah memperbaikinya. Begitu:
Perhatikan bahwa ini berarti banyak saran kuat tentang tes unit tidak selalu berlaku untuk tes nondeterministik. Misalnya, mereka harus cepat. Tes properti tingkat rendah harus cepat, tetapi tes nondeterministik seperti "mensimulasikan pengguna mengklik tombol secara acak di situs web Anda dan pastikan Anda tidak pernah mendapatkan 500 kesalahan" harus mendukung kelengkapan daripada kecepatan. Hanya memiliki tes seperti itu yang berjalan secara independen dari proses build Anda sehingga tidak memperlambat pengembangan. Misalnya, jalankan di kotak pementasan pribadi.
sumber
Anda tidak benar-benar ingin deterministik vs non-deterministik.
Apa yang Anda inginkan adalah "selalu sama" vs. "tidak selalu sama".
Misalnya, Anda mungkin memiliki nomor build yang meningkat dengan setiap build, dan ketika Anda menginginkan beberapa nomor acak, Anda menginisialisasi generator angka acak dengan nomor build sebagai seed. Jadi setiap build, Anda melakukan pengujian dengan nilai yang berbeda, memberi Anda lebih banyak peluang untuk menemukan bug.
Tetapi begitu bug ditemukan, yang perlu Anda lakukan adalah menjalankan tes dengan nomor build yang sama, dan itu dapat direproduksi.
sumber