Data acak dalam Tes Unit?

139

Saya memiliki rekan kerja yang menulis pengujian unit untuk objek yang mengisi bidangnya dengan data acak. Alasannya adalah memberikan pengujian yang lebih luas, karena akan menguji banyak nilai yang berbeda, sedangkan pengujian normal hanya menggunakan satu nilai statis.

Saya telah memberinya sejumlah alasan berbeda untuk melawan ini, yang utama adalah:

  • nilai acak berarti pengujian tidak benar-benar dapat diulang (yang juga berarti bahwa jika pengujian dapat gagal secara acak, pengujian dapat dilakukan di server build dan merusak build)
  • jika itu adalah nilai acak dan pengujian gagal, kita perlu a) memperbaiki objek dan b) memaksa diri kita sendiri untuk menguji nilai itu setiap saat, jadi kita tahu itu berhasil, tetapi karena ini acak kita tidak tahu apa nilainya

Rekan kerja lain menambahkan:

  • Jika saya menguji pengecualian, nilai acak tidak akan memastikan bahwa pengujian berakhir dalam keadaan yang diharapkan
  • data acak digunakan untuk membersihkan sistem dan pengujian beban, bukan untuk pengujian unit

Adakah yang bisa menambahkan alasan tambahan yang bisa saya berikan padanya untuk membuatnya berhenti melakukan ini?

(Atau sebaliknya, apakah ini metode penulisan tes unit yang dapat diterima, dan saya serta rekan kerja saya yang lain salah?)

Adam V
sumber
34
"nilai acak berarti pengujian tidak benar-benar dapat diulang" tidak benar, karena tet akan menggunakan nomor acak semu. Berikan benih awal yang sama, dapatkan urutan tes "acak" yang sama.
Raedwald
11
Anekdot: Saya pernah menulis kelas ekspor CSV, dan pengujian acak mengungkapkan bug ketika karakter kontrol ditempatkan di akhir sel. Tanpa pengujian acak, saya tidak akan pernah berpikir untuk menambahkannya sebagai kasus uji. Apakah selalu gagal? Tidak. Apakah ini ujian yang sempurna? Tidak. Apakah itu membantu saya menangkap dan memperbaiki bug? Iya.
Tyzoid
1
Tes juga dapat berfungsi sebagai dokumentasi, untuk menjelaskan kapan kode diharapkan sebagai masukan dan apa yang diharapkan sebagai keluaran. Melakukan pengujian dengan data arbitrer yang jelas bisa lebih sederhana dan lebih jelas daripada kode yang menghasilkan data acak.
splintor
Jika unit test Anda gagal karena nilai yang dihasilkan secara acak, dan nilai ini bukan bagian dari assert, semoga berhasil dengan debugging unit test Anda.
eriksmith200

Jawaban:

76

Ada kompromi. Rekan kerja Anda sebenarnya tertarik pada sesuatu, tetapi saya pikir dia salah melakukannya. Saya tidak yakin bahwa pengujian yang benar-benar acak sangat berguna, tetapi tentu saja tidak valid.

Spesifikasi program (atau unit) adalah hipotesis bahwa terdapat beberapa program yang memenuhi itu. Program itu sendiri kemudian menjadi bukti hipotesis itu. Pengujian unit yang seharusnya adalah upaya untuk memberikan bukti tandingan untuk menyangkal bahwa program bekerja sesuai dengan spesifikasi.

Sekarang, Anda dapat menulis pengujian unit dengan tangan, tetapi ini benar-benar merupakan tugas mekanis. Itu bisa otomatis. Yang harus Anda lakukan adalah menulis spesifikasi, dan mesin dapat menghasilkan banyak sekali pengujian unit yang mencoba memecahkan kode Anda.

Saya tidak tahu bahasa apa yang Anda gunakan, tapi lihat di sini:

Java http://functionaljava.org/

Scala (atau Java) http://github.com/rickynils/scalacheck

Haskell http://www.cs.chalmers.se/~rjmh/QuickCheck/

.NET: http://blogs.msdn.com/dsyme/archive/2008/08/09/fscheck-0-2.aspx

Alat-alat ini akan mengambil spesifikasi Anda yang telah dibentuk dengan baik sebagai masukan dan secara otomatis menghasilkan pengujian unit sebanyak yang Anda inginkan, dengan data yang dibuat secara otomatis. Mereka menggunakan strategi "menyusut" (yang dapat Anda sesuaikan) untuk menemukan kasus uji yang paling sederhana untuk memecahkan kode Anda dan untuk memastikannya mencakup kasus tepi dengan baik.

Selamat menguji!

Apocalisp
sumber
2
+1 untuk ini. ScalaCheck melakukan pekerjaan fenomenal dalam menghasilkan data uji acak yang diminimalkan dengan cara yang dapat diulang.
Daniel Spiewak
17
Itu tidak acak. Itu sewenang-wenang. Perbedaan besar :)
Apocalisp
reductiotest.org sekarang sepertinya sudah ada lagi, dan Google tidak mengarahkan saya ke tempat lain. Tahu dimana sekarang?
Raedwald
Sekarang bagian dari perpustakaan Java Fungsional. Tautan diedit. Tapi saya hanya akan menggunakan Scalacheck untuk menguji kode Java.
Apocalisp
ScalaCheck telah pindah ke GitHub. Tautan diperbarui dalam jawaban. Ini juga berguna untuk Java, bukan hanya Scala. (Tautan lama adalah code.google.com/p/scalacheck )
RobertB
40

Jenis pengujian ini disebut pengujian Monkey . Jika dilakukan dengan benar, itu bisa mengeluarkan serangga dari sudut yang benar-benar gelap.

Untuk mengatasi kekhawatiran Anda tentang reproduktifitas: cara yang tepat untuk melakukan ini, adalah dengan merekam entri tes yang gagal, menghasilkan tes unit, yang menyelidiki seluruh keluarga dari bug tertentu; dan termasuk dalam pengujian unit satu input spesifik (dari data acak) yang menyebabkan kegagalan awal.

Naga Perak
sumber
27

Ada rumah singgah di sini yang memiliki beberapa kegunaan, yaitu untuk menyemai PRNG Anda dengan konstan. Itu memungkinkan Anda untuk menghasilkan data 'acak' yang dapat diulang.

Secara pribadi saya pikir ada tempat di mana data acak (konstan) berguna dalam pengujian - setelah Anda pikir Anda telah melakukan semua sudut yang dipikirkan dengan cermat, menggunakan rangsangan dari PRNG terkadang dapat menemukan hal-hal lain.

Will Dean
sumber
4
Saya telah melihat ini bekerja dengan baik pada sistem yang memiliki banyak penguncian dan utas. Benih 'acak' ditulis ke file pada setiap proses, kemudian jika proses gagal, kami dapat menentukan jalur yang diambil kode dan menulis tes unit yang ditulis tangan untuk kasus yang kami lewatkan.
Ian Ringrose
Apa kepanjangan PRNG?
systemovich
Generator Nomor Acak Pseudo
Akan Dekan
17

Dalam buku Beautiful Code , ada bab yang berjudul "Beautiful Tests", di mana dia membahas strategi pengujian untuk algoritma Binary Search . Satu paragraf disebut "Tindakan Pengujian Acak", di mana dia membuat susunan acak untuk menguji algoritme secara menyeluruh. Anda dapat membaca beberapa di antaranya secara online di Google Buku, halaman 95 , tetapi ini adalah buku yang sangat berharga.

Jadi pada dasarnya ini hanya menunjukkan bahwa menghasilkan data acak untuk pengujian adalah opsi yang layak.

mreggen.dll
sumber
16

Saya mendukung tes acak, dan saya menulisnya. Namun, apakah mereka sesuai dalam lingkungan build tertentu dan suite pengujian mana yang harus disertakan adalah pertanyaan yang lebih bernuansa.

Jalankan secara lokal (misalnya, semalaman di kotak dev Anda) tes acak telah menemukan bug yang jelas dan tidak jelas. Yang tidak jelas cukup misterius sehingga saya pikir pengujian acak benar-benar satu-satunya yang realistis untuk menghilangkannya. Sebagai ujian, saya mengambil satu bug yang sulit ditemukan yang ditemukan melalui pengujian acak dan meminta setengah lusin pengembang crack meninjau fungsi (sekitar selusin baris kode) tempat terjadinya. Tidak ada yang bisa mendeteksinya.

Banyak argumen Anda terhadap data acak adalah bentuk dari "pengujian tidak dapat direproduksi". Namun, tes acak yang ditulis dengan baik akan menangkap benih yang digunakan untuk memulai benih acak dan mengeluarkannya jika gagal. Selain memungkinkan Anda mengulangi pengujian dengan tangan, ini memungkinkan Anda membuat pengujian baru yang menguji masalah tertentu secara mudah dengan melakukan hardcode seed untuk pengujian tersebut. Tentu saja, mungkin lebih baik untuk memberi kode tangan pada tes eksplisit yang mencakup kasus itu, tetapi kemalasan memiliki kelebihan, dan ini bahkan memungkinkan Anda untuk secara otomatis menghasilkan kasus uji baru dari seed yang gagal.

Namun, satu hal yang Anda buat yang tidak dapat saya perdebatkan adalah bahwa hal itu merusak sistem build. Sebagian besar pengujian build dan continuous integration mengharapkan pengujian melakukan hal yang sama, setiap saat. Jadi tes yang gagal secara acak akan menciptakan kekacauan, gagal secara acak dan menunjukkan perubahan yang tidak berbahaya.

Solusinya adalah dengan tetap menjalankan pengujian acak Anda sebagai bagian dari pengujian build dan CI, tetapi menjalankannya dengan seed tetap, untuk sejumlah iterasi tetap . Oleh karena itu, pengujian selalu melakukan hal yang sama, tetapi masih mengeksplorasi sekumpulan ruang input (jika Anda menjalankannya untuk beberapa iterasi).

Secara lokal, misalnya, saat mengubah kelas terkait, Anda bebas menjalankannya untuk lebih banyak iterasi atau dengan seed lain. Jika pengujian acak menjadi lebih populer, Anda bahkan dapat membayangkan rangkaian pengujian tertentu yang diketahui acak, yang dapat dijalankan dengan benih yang berbeda (karenanya dengan cakupan yang meningkat dari waktu ke waktu), dan di mana kegagalan tidak berarti hal yang sama sebagai sistem CI deterministik (yaitu, proses tidak terkait 1: 1 dengan perubahan kode sehingga Anda tidak perlu menunjuk perubahan tertentu ketika ada yang gagal).

Ada banyak hal yang bisa dikatakan tentang tes acak, terutama tes yang ditulis dengan baik, jadi jangan terlalu cepat mengabaikannya!

BeeOnRope
sumber
15

Jika Anda melakukan TDD maka saya berpendapat bahwa data acak adalah pendekatan yang sangat baik. Jika pengujian Anda ditulis dengan konstanta, Anda hanya dapat menjamin kode Anda berfungsi untuk nilai tertentu. Jika pengujian Anda gagal secara acak server build, kemungkinan ada masalah dengan cara pengujian ditulis.

Data acak akan membantu memastikan pemfaktoran ulang di masa mendatang tidak akan bergantung pada konstanta ajaib. Lagi pula, jika pengujian Anda adalah dokumentasi Anda, bukankah keberadaan konstanta menyiratkan bahwa hanya perlu berfungsi untuk konstanta tersebut?

Saya melebih-lebihkan namun saya lebih suka menyuntikkan data acak ke dalam pengujian saya sebagai tanda bahwa "nilai variabel ini seharusnya tidak memengaruhi hasil pengujian ini".

Saya akan mengatakan bahwa jika Anda menggunakan variabel acak kemudian membagi tes Anda berdasarkan variabel itu, maka itu adalah bau.

Jimmy Bosse
sumber
10

Rekan kerja Anda sedang melakukan pengujian fuzz , meskipun dia tidak mengetahuinya. Mereka sangat berharga dalam sistem server.

Robert Gould
sumber
2
tetapi bukankah ini hal yang secara fundamental berbeda dari pengujian unit? dan dilakukan pada waktu yang berbeda?
endolith
2
@endolith tidak ada hukum fisika yang memaksa Anda untuk menjalankan tes tertentu pada waktu tertentu
user253751
1
@immibis Tapi ada alasan bagus untuk melakukan tes tertentu pada waktu tertentu. Anda tidak menjalankan pengujian unit baterai setiap kali pengguna mengklik tombol "Ok".
endolith
@ user253751 Saya rasa kita harus mencetak beberapa kaos dengan kutipan Anda! :)
Kirby
10

Satu keuntungan bagi seseorang yang melihat tes adalah bahwa data yang berubah-ubah jelas tidak penting. Saya telah melihat terlalu banyak tes yang melibatkan lusinan potongan data dan sulit untuk mengatakan apa yang perlu dilakukan seperti itu dan apa yang kebetulan seperti itu. Misalnya, jika metode validasi alamat diuji dengan kode pos tertentu dan semua data lainnya acak, maka Anda dapat yakin bahwa kode pos adalah satu-satunya bagian penting.

Trystan Spangler
sumber
9
  • jika itu adalah nilai acak dan pengujian gagal, kita perlu a) memperbaiki objek dan b) memaksa diri kita sendiri untuk menguji nilai itu setiap saat, jadi kita tahu itu berhasil, tetapi karena ini acak kita tidak tahu apa nilainya

Jika kasus pengujian Anda tidak secara akurat mencatat apa yang diuji, mungkin Anda perlu membuat kode ulang kasus pengujian. Saya selalu ingin memiliki log yang dapat saya rujuk kembali untuk kasus pengujian sehingga saya tahu persis apa yang menyebabkannya gagal apakah menggunakan data statis atau acak.

EBGreen
sumber
4

Dapatkah Anda menghasilkan beberapa data acak sekali (maksud saya persis sekali, bukan sekali per uji coba), lalu menggunakannya di semua pengujian setelahnya?

Saya pasti dapat melihat nilai dalam membuat data acak untuk menguji kasus-kasus yang belum Anda pikirkan, tetapi Anda benar, memiliki pengujian unit yang dapat lulus atau gagal secara acak adalah hal yang buruk.

Programmer Penjahat
sumber
4

Anda harus bertanya pada diri sendiri apa tujuan ujian Anda.
Tes unit adalah tentang memverifikasi logika, aliran kode, dan interaksi objek. Menggunakan nilai acak mencoba mencapai tujuan yang berbeda, sehingga mengurangi fokus pengujian dan kesederhanaan. Ini dapat diterima karena alasan keterbacaan (menghasilkan UUID, id, kunci, dll.).
Khusus untuk unit test, saya tidak dapat mengingatnya walaupun metode ini berhasil menemukan masalah. Tetapi saya telah melihat banyak masalah determinisme (dalam tes) mencoba menjadi pandai dengan nilai acak dan terutama dengan tanggal acak.
Pengujian fuzz adalah pendekatan yang valid untuk pengujian integrasi dan pengujian ujung ke ujung .

Ohad Bruker
sumber
Saya akan menambahkan bahwa menggunakan input acak untuk fuzzing adalah pengganti yang buruk untuk fuzzing yang dipandu cakupan bila memungkinkan.
gobenji
2

Jika Anda menggunakan input acak untuk pengujian Anda, Anda perlu mencatat input sehingga Anda dapat melihat nilainya. Dengan cara ini jika ada kasus tepi yang Anda temui, Anda dapat menulis tes untuk mereproduksinya. Saya pernah mendengar alasan yang sama dari orang-orang untuk tidak menggunakan input acak, tetapi begitu Anda memiliki wawasan tentang nilai aktual yang digunakan untuk uji coba tertentu, itu bukan masalah yang besar.

Pengertian “sembarang” data juga sangat berguna sebagai cara menandakan sesuatu yang tidak penting. Kami memiliki beberapa tes penerimaan yang terlintas dalam pikiran di mana ada banyak data gangguan yang tidak relevan dengan tes yang ada.

craigb.dll
sumber
0

Bergantung pada objek / aplikasi Anda, data acak akan memiliki tempat dalam pengujian beban. Saya pikir yang lebih penting adalah menggunakan data yang secara eksplisit menguji kondisi batas data.

EBGreen
sumber
0

Kami baru saja mengalami ini hari ini. Saya ingin pseudo-random (jadi akan terlihat seperti data audio terkompresi dalam hal ukuran). Saya TODO bahwa saya juga ingin deterministik . rand () berbeda di OSX daripada di Linux. Dan kecuali saya melakukan seeding ulang, itu bisa berubah kapan saja. Jadi kami mengubahnya menjadi deterministik tetapi tetap psuedo-random: pengujian ini dapat diulangi, sama seperti menggunakan data kaleng (tetapi lebih mudah ditulis).

Ini BUKAN diuji oleh beberapa kekerasan acak melalui jalur kode. Itulah perbedaannya: masih deterministik, masih berulang, masih menggunakan data yang terlihat seperti input nyata untuk menjalankan serangkaian pemeriksaan menarik pada kasus edge dalam logika yang kompleks. Masih unit tes.

Apakah yang masih memenuhi syarat itu acak? Mari kita bicara tentang bir. :-)

Tim James
sumber
0

Saya dapat membayangkan tiga solusi untuk masalah data pengujian:

  • Uji dengan data tetap
  • Uji dengan data acak
  • Hasilkan data acak sekali , lalu gunakan sebagai data tetap Anda

Saya akan merekomendasikan melakukan semua hal di atas . Artinya, tulis pengujian unit yang dapat diulang dengan kedua kasus tepi bekerja menggunakan otak Anda, dan beberapa data acak yang Anda buat hanya sekali. Kemudian tulis serangkaian pengujian acak yang Anda jalankan juga .

Tes acak tidak boleh diharapkan untuk menangkap sesuatu yang luput dari tes berulang Anda. Anda harus bertujuan untuk mencakup semuanya dengan tes berulang, dan menganggap tes acak sebagai bonus. Jika mereka menemukan sesuatu, itu haruslah sesuatu yang tidak dapat Anda prediksi secara masuk akal; eksentrik yang nyata.

Tom W.
sumber
-3

Bagaimana cowok Anda bisa menjalankan tes lagi ketika gagal untuk melihat apakah dia telah memperbaikinya? Yaitu dia kehilangan pengulangan tes.

Meskipun saya pikir mungkin ada beberapa nilai dalam melemparkan beban data acak pada pengujian, seperti yang disebutkan dalam balasan lain, hal itu lebih termasuk dalam judul pengujian beban daripada yang lainnya. Ini adalah praktik "menguji dengan harapan". Saya pikir, pada kenyataannya, pria Anda sama sekali tidak memikirkan tentang apa yang dia coba uji, dan mengganti kekurangan pemikiran itu dengan berharap keacakan pada akhirnya akan menjebak beberapa kesalahan misterius.

Jadi argumen yang akan saya gunakan dengannya adalah bahwa dia malas. Atau, dengan kata lain, jika dia tidak meluangkan waktu untuk memahami apa yang dia coba uji, itu mungkin menunjukkan dia tidak benar-benar memahami kode yang dia tulis.

Greg Whitfield
sumber
3
Dimungkinkan untuk mencatat data acak atau benih acak sehingga tes dapat direproduksi.
cbp
selain mencatat angka acak, umumnya tes yang gagal dengan input acak, bahkan jika input acak tidak dicatat, tes itu dapat dijalankan kembali dalam satu while(true)putaran dan kemungkinan besar akan gagal dalam waktu yang diperlukan untuk memeriksa Anda. umpan snapchat.
Kirby