Apakah tes unit penulisan manual Bukti Dengan Contoh?


9

Kita tahu bahwa menulis tes JUnit menunjukkan satu jalur tertentu melalui kode Anda.

Salah satu rekan saya berkomentar:

Tes unit yang ditulis secara manual adalah Proof By Example .

Dia berasal dari latar belakang Haskell yang memiliki alat seperti Quickcheck dan kemampuan untuk berpikir tentang perilaku program dengan tipe .

Implikasinya adalah bahwa ada banyak kombinasi input lain yang belum dicoba oleh metode ini yang kode Anda tidak diuji.

Pertanyaan saya adalah: Apakah penulisan unit secara manual membuktikan dengan contoh?


3
Tidak, tidak menulis / menggunakan tes. Mengklaim bahwa pengujian unit Anda adalah bukti bahwa tidak ada yang salah dengan program ini adalah Bukti dengan Contoh (generalisasi yang tidak sesuai). Tes bukan tentang pembuktian kode secara matematis - tes, berdasarkan sifatnya, merupakan pemeriksaan eksperimental. Ini adalah jaring pengaman yang membantu Anda membangun kepercayaan diri dengan memberi tahu Anda sesuatu tentang kode tersebut. Tetapi Andalah yang harus memilih strategi yang baik untuk menyelidiki kode, dan Andalah yang harus menafsirkan apa artinya data itu.
Filip Milovanović

Jawaban:


10

Jika Anda secara acak memilih input untuk pengujian, maka saya kira itu mungkin bahwa Anda menggunakan Bukti dengan Contoh yang salah.

Tetapi unit test yang baik tidak pernah melakukan itu. Sebaliknya, mereka menangani rentang dan tepi kasus.

Misalnya, jika Anda menulis tes unit untuk fungsi nilai absolut yang menerima integer sebagai input, Anda tidak perlu menguji setiap nilai input yang mungkin untuk membuktikan bahwa kode berfungsi. Untuk mendapatkan tes komprehensif, Anda hanya perlu lima nilai: -1, 0, 1, dan nilai maks dan min untuk bilangan bulat input.

Kelima nilai ini menguji setiap kemungkinan rentang dan tepi kasus fungsi. Anda tidak perlu menguji setiap nilai input yang mungkin lainnya (yaitu setiap angka yang dapat diwakili oleh tipe integer) untuk mendapatkan tingkat kepercayaan tinggi bahwa fungsi tersebut bekerja untuk semua nilai input.


11
Penguji kode memasuki bar dan memesan bir. 5 bir. -1 bir, bir MAX_VALUE, seekor ayam. sebuah nol.
Neil

2
"5 nilai" adalah omong kosong. Pertimbangkan fungsi sepele seperti int foo(int x) { return 1234/(x - 100); }. Perhatikan juga bahwa (tergantung pada apa yang Anda uji), Anda mungkin perlu memastikan bahwa input yang tidak valid ("di luar jangkauan") mengembalikan hasil yang benar (mis. `` Find_thing (thing) `dengan benar mengembalikan semacam status" tidak ditemukan "dengan benar jika benda itu tidak ditemukan).
Brendan

3
@ Brendan: Tidak ada yang signifikan tentang hal itu menjadi lima nilai; kebetulan saja ada lima nilai dalam contoh saya. Contoh Anda memiliki jumlah tes yang berbeda karena Anda menguji fungsi yang berbeda. Saya tidak mengatakan bahwa setiap fungsi membutuhkan tepat lima tes; Anda menyimpulkan bahwa dari membaca jawaban saya.
Robert Harvey

1
Pustaka pengujian generatif biasanya lebih baik dalam menguji kasus tepi daripada Anda. Jika, misalnya, Anda menggunakan mengapung bukan bilangan bulat, perpustakaan Anda juga akan memeriksa -Inf, Inf, NaN, 1e-100, -1e-100, -0, 2e200... aku lebih suka tidak perlu melakukan hal-semua secara manual.
Hovercouch

@Hovercouch: Jika Anda tahu yang bagus, saya ingin mendengarnya. Yang terbaik yang pernah saya lihat adalah Pex; itu sangat tidak stabil. Ingat, kita berbicara tentang fungsi yang relatif sederhana di sini. Banyak hal menjadi lebih sulit ketika Anda berurusan dengan hal-hal seperti logika bisnis kehidupan nyata.
Robert Harvey

8

Setiap pengujian perangkat lunak seperti "Bukti Dengan Contoh", tidak hanya pengujian unit menggunakan alat seperti JUnit. Dan itu bukan kebijaksanaan baru, ada kutipan dari Dijkstra dari tahun 1960, yang pada dasarnya mengatakan hal yang sama:

"Pengujian menunjukkan ada, bukan tidak adanya bug"

(cukup ganti kata "menunjukkan" dengan "bukti"). Namun, ini juga berlaku untuk alat yang menghasilkan data uji acak. Jumlah input yang mungkin untuk fungsi dunia nyata biasanya lebih besar berdasarkan urutan besarnya daripada jumlah kasus uji yang dapat dihasilkan dan diverifikasi terhadap hasil yang diharapkan dalam usia alam semesta, terlepas dari metode pembuatan kasus tersebut, jadi bahkan jika seseorang menggunakan alat generator untuk menghasilkan banyak data pengujian, tidak ada jaminan untuk tidak melewatkan satu test case yang dapat mendeteksi bug tertentu.

Tes acak terkadang dapat mengungkapkan bug yang diabaikan oleh kasus uji yang dibuat secara manual. Tetapi secara umum, lebih efisien untuk membuat tes dengan hati-hati terhadap fungsi yang akan diuji, dan memastikan seseorang mendapatkan kode lengkap dan cakupan cabang dengan sesedikit mungkin kasus uji. Kadang-kadang itu adalah strategi yang layak untuk menggabungkan tes yang dihasilkan secara manual dan acak. Terlebih lagi, ketika menggunakan tes acak, seseorang harus berhati-hati untuk mendapatkan hasilnya secara berulang.

Jadi tes yang dibuat secara manual sama sekali tidak lebih buruk daripada tes yang dibuat secara acak, seringkali justru sebaliknya.


1
Setiap test suite praktis menggunakan pengecekan acak juga akan memiliki unit test. (Secara teknis, tes unit hanya merupakan kasus pengujian acak yang merosot.) Kata-kata Anda menunjukkan bahwa tes acak sulit untuk dicapai, atau bahwa menggabungkan pengujian acak dan tes unit sulit dilakukan. Ini biasanya tidak demikian. Menurut pendapat saya, salah satu manfaat terbesar dari pengujian acak adalah sangat mendorong pengujian penulisan sebagai properti tentang kode yang dimaksudkan untuk selalu berlaku. Saya lebih suka memiliki sifat-sifat ini secara eksplisit dinyatakan (dan diperiksa!) Daripada harus menyimpulkannya beberapa tes poin.
Derek Elkins meninggalkan SE

@DerekElkins: "sulit" adalah istilah yang salah IMHO. Tes acak memerlukan cukup banyak upaya, dan itu adalah upaya yang mengurangi waktu yang tersedia untuk tes kerajinan tangan (dan jika Anda memiliki orang yang hanya mengikuti slogan seperti yang disebutkan dalam pertanyaan, mereka mungkin tidak akan membuat kerajinan tangan sama sekali). Hanya melempar banyak data uji acak pada sepotong kode hanya setengah pekerjaan, satu juga harus menghasilkan hasil yang diharapkan untuk masing-masing input tes. Untuk beberapa skenario, ini dapat dilakukan secara otomatis. Bagi yang lain, tidak.
Doc Brown

Meskipun ada saat-saat tertentu di mana beberapa pemikiran diperlukan untuk memilih distribusi yang baik, ini biasanya bukan penutupan utama. Komentar Anda menunjukkan bahwa Anda memikirkan hal ini dengan cara yang salah. Properti yang Anda tulis untuk pengecekan acak adalah properti yang sama dengan yang Anda tulis untuk pengecekan model atau untuk bukti formal. Memang, mereka dapat dan telah digunakan untuk semua hal itu pada saat yang sama. Tidak ada "hasil yang diharapkan" yang perlu Anda hasilkan juga. Sebaliknya, Anda cukup menyatakan properti yang harus selalu dimiliki. Beberapa contoh: 1) mendorong sesuatu ke tumpukan dan ...
Derek Elkins meninggalkan SE

... maka bermunculan harus sama dengan tidak melakukan apa-apa; 2) setiap pelanggan dengan saldo lebih dari $ 10.000 harus mendapatkan suku bunga saldo tinggi dan hanya kemudian; 3) posisi sprite selalu berada di dalam kotak pembatas layar. Beberapa properti mungkin berhubungan dengan tes titik misalnya "ketika saldo adalah $ 0 memberikan peringatan saldo nol". Properti adalah spesifikasi parsial dengan ideal mendapatkan spesifikasi total. Memiliki kesulitan memikirkan sifat-sifat ini berarti Anda tidak jelas tentang spesifikasi dan sering kali berarti Anda akan mengalami kesulitan memikirkan tes unit yang baik.
Derek Elkins meninggalkan SE

0

Tes menulis secara manual adalah "bukti dengan contoh". Tapi begitu juga QuickCheck, dan untuk sistem tipe terbatas. Apa pun yang bukan verifikasi formal langsung akan dibatasi dalam hal yang memberi tahu Anda tentang kode Anda. Sebaliknya, Anda harus berpikir dalam kaitannya dengan manfaat relatif dari pendekatan.

Pengujian generatif, seperti QuickCheck, sangat bagus untuk menyapu ruang input yang luas. Ini juga jauh lebih baik untuk menangani kasus tepi daripada tes manual: perpustakaan pengujian generatif akan lebih berpengalaman dengan ini daripada Anda. Di sisi lain, mereka hanya memberi tahu Anda tentang invarian, bukan output spesifik. Jadi untuk memvalidasi program Anda mendapatkan hasil yang benar, Anda masih memerlukan beberapa tes manual untuk memverifikasi itu, pada kenyataannya foo(bar) = baz,.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.