Pengujian unit untuk perpustakaan komputasi ilmiah

15

Saya sudah memiliki sedikit pengalaman dengan pengujian unit sebelumnya, dalam apa yang saya sebut (tidak merendahkan) proyek rekayasa perangkat lunak klasik: sebuah MVC, dengan GUI pengguna, database, logika bisnis di lapisan tengah, dll. Sekarang saya ' m menulis perpustakaan komputasi ilmiah di C # (yeah, saya tahu C # terlalu lambat, gunakan C, jangan menemukan kembali roda, dan semua itu, tapi kami memiliki banyak orang melakukan perhitungan ilmiah di fakultas saya di C #, dan kami membutuhkannya). Ini adalah proyek kecil, dalam hal industri pengembangan perangkat lunak, karena saya menulis sebagian besar sendiri, dan dari waktu ke waktu dengan bantuan beberapa rekan. Juga, saya tidak dibayar untuk itu, dan yang paling penting, adalah proyek akademik. Maksud saya, saya berharap ini memiliki kualitas profesional suatu hari nanti, karena saya berencana untuk open source,

Bagaimanapun, proyek ini semakin besar (sekitar 18.000 baris kode, yang saya pikir besar untuk proyek satu orang), dan keluar dari tangan saya. Saya menggunakan git untuk kontrol sumber, dan saya pikir saya sudah cukup baik-baik saja, tapi saya menguji seperti jadul, maksud saya, menulis aplikasi konsol penuh yang menguji sebagian besar sistem, terutama karena saya tidak tahu caranya untuk melakukan pengujian unit dalam skenario ini, meskipun saya merasa itulah yang harus saya lakukan. Masalahnya adalah bahwa perpustakaan sebagian besar berisi algoritma, misalnya, algoritma grafik, pengklasifikasi, pemecah angka, distribusi acak, dll. Saya hanya tidak tahu bagaimana menentukan kasus uji kecil untuk masing-masing algoritma ini, dan karena banyak dari mereka adalah stochastic Saya tidak tahu bagaimana memvalidasi kebenaran. Untuk klasifikasi, misalnya, adalah beberapa metrik seperti presisi dan penarikan, tetapi metrik ini lebih baik untuk membandingkan dua algoritma daripada menilai algoritma tunggal. Jadi, bagaimana saya bisa mendefinisikan kebenaran di sini?

Akhirnya ada juga masalah kinerja. Saya tahu ini adalah serangkaian tes yang berbeda, tetapi kinerja adalah salah satu fitur penting dari alat ilmiah, daripada kepuasan pengguna, atau metrik rekayasa perangkat lunak lainnya.

Salah satu masalah terbesar saya adalah dengan struktur data. Satu-satunya tes yang dapat saya lakukan untuk kd-tree adalah tes stres: memasukkan banyak vektor acak dan kemudian melakukan banyak pertanyaan acak, dan membandingkannya dengan pencarian linear yang naif. Sama untuk kinerja. Dan dengan pengoptimal numerik, saya memiliki fungsi tolok ukur yang dapat saya uji, tetapi sekali lagi, ini adalah tes stres. Saya tidak berpikir tes ini dapat digolongkan sebagai unit test, dan yang paling penting, berjalan terus menerus, karena kebanyakan dari mereka agak berat. Tapi saya juga berpikir bahwa tes ini perlu dilakukan, saya tidak bisa hanya memasukkan dua elemen, pop root, dan ya, itu berfungsi untuk case 0-1-n.

Jadi, apa, jika ada, pendekatan pengujian (unit) untuk perangkat lunak semacam ini? Dan bagaimana cara mengatur tes unit dan yang berat di sekitar siklus code-build-commit-integr?

Alejandro Piad
sumber

Jawaban:

19

Saya akan mengatakan bahwa komputasi ilmiah sebenarnya cukup cocok untuk pengujian unit. Anda memiliki input dan output yang pasti, prekondisi dan pascakondisi yang jelas yang mungkin tidak akan berubah setiap minggu sesuai dengan keinginan beberapa desainer, dan tidak ada persyaratan UI yang sulit untuk diuji.

Anda menyebutkan beberapa elemen yang dapat menyebabkan masalah; inilah yang harus dilakukan tentang mereka:

  • algoritma acak: ada dua kemungkinan. Jika Anda benar-benar ingin menguji pengacakan itu sendiri, cukup jadwalkan sejumlah besar pengulangan dan nyatakan bahwa proporsi kasus yang diharapkan memenuhi kriteria yang diinginkan, dengan margin kesalahan yang cukup besar sehingga kegagalan pengujian palsu akan sangat jarang. (Sebuah test suite yang sangat menandakan bug phantom banyak lebih buruk daripada yang tidak menangkap setiap cacat yang mungkin terjadi.) Atau, gunakan sumber acak yang dapat dikonfigurasi dan ganti jam sistem (atau apa pun yang Anda gunakan) dengan sumber deterministik melalui ketergantungan. injeksi sehingga tes Anda menjadi sepenuhnya dapat diprediksi.
  • algoritma yang didefinisikan hanya dalam hal presisi / penarikan: tidak ada yang menghentikan Anda untuk memasukkan seluruh rangkaian kasus input dan mengukur presisi dan mengingat dengan menambahkan semuanya; itu hanya masalah semi-otomatis menghasilkan kasus uji seperti itu secara efisien sehingga memberikan data uji tidak menjadi hambatan bagi produktivitas Anda. Sebagai alternatif, menspesifikasikan beberapa pasangan input / output yang dipilih secara bijak dan menyatakan bahwa algoritma menghitung dengan tepat input yang diinginkan juga dapat berfungsi jika rutinitasnya cukup dapat diprediksi.
  • persyaratan non-fungsional: Jika spesifikasi benar-benar memberikan persyaratan ruang / waktu yang eksplisit, maka pada dasarnya Anda harus menjalankan seluruh rangkaian pasangan input / output dan memverifikasi bahwa penggunaan sumber daya sesuai sekitar untuk pola penggunaan yang diperlukan. Kuncinya di sini adalah mengkalibrasi kelas tes Anda sendiri terlebih dahulu, sehingga Anda tidak mengukur sepuluh masalah dengan ukuran berbeda yang akhirnya terlalu cepat untuk diukur, atau yang memakan waktu begitu lama sehingga menjalankan test suite menjadi tidak praktis. Anda bahkan dapat menulis generator use case kecil yang membuat test case dengan ukuran berbeda, tergantung seberapa cepat PU berjalan.
  • tes cepat dan lambat: apakah itu tes unit atau integrasi, Anda sering berakhir dengan banyak tes sangat cepat dan beberapa yang sangat lambat. Karena menjalankan tes Anda secara teratur sangat berharga, saya biasanya menempuh jalur pragmatis dan memisahkan semua yang saya miliki menjadi paket cepat dan lambat, sehingga tes cepat dapat dijalankan sesering mungkin (tentu sebelum setiap komit), dan tidak peduli apakah dua tes 'semantik' milik bersama atau tidak.
Kilian Foth
sumber
+1. Terima kasih banyak, ada banyak wawasan jika jawaban Anda. Hanya beberapa pertanyaan: Bagaimana dengan algoritma optimasi seperti meta-heuristics. Saya memiliki banyak fungsi benchmark, tetapi yang bisa saya lakukan dengan mereka adalah membandingkan dua algoritma yang berbeda. Apakah saya perlu mencari algoritma benchmark juga? Apa artinya algoritma genetika benar? Dan bagaimana saya menguji setiap strategi "parameterabel", seperti jenis rekombinasi dan mutasi, dll?
Alejandro Piad
1
Untuk meta-heuristik, saya setuju untuk memilih beberapa pasangan I / O karakteristik, yaitu "keberhasilan terkenal" rutin, dan memverifikasi bahwa metode (atau yang lebih baik dari keduanya) ternyata menemukan solusi ini. Masalah "memetik ceri" yang bekerja dengan baik tentu saja adalah tidak-tidak dalam penelitian optimasi, tetapi untuk pengujian perangkat lunak yang tidak menjadi perhatian - Anda tidak menyatakan kualitas algoritme, hanya implementasi yang benar. Itulah satu-satunya "kebenaran" yang dapat Anda buktikan. Adapun rutinitas yang dapat dialiri banyak kali lipat: ya, saya khawatir itu membutuhkan sejumlah tes kombinasi ...
Kilian Foth
Jadi itu seperti merancang patokan sepele bahwa semua implementasi yang benar harus menyelesaikan dengan tepat? Apakah ada cara untuk membuktikan kualitas algoritma? Saya tahu bahwa saya tidak dapat mendefinisikan standar kualitas sebagian besar waktu, tetapi setidaknya saya bisa berharap bahwa tidak ada perubahan yang menurunkan kualitas yang dicapai?
Alejandro Piad