Apakah bermanfaat untuk menulis tes unit untuk kode penelitian ilmiah?

89

Saya sangat yakin akan nilai menggunakan tes yang memverifikasi program lengkap (misalnya tes konvergensi), termasuk serangkaian uji regresi otomatis . Setelah membaca beberapa buku pemrograman, saya merasa ngeri bahwa saya "harus" menulis unit test (yaitu, tes yang memverifikasi kebenaran fungsi tunggal dan tidak sama dengan menjalankan seluruh kode untuk menyelesaikan masalah) juga . Namun, tes unit tampaknya tidak selalu sesuai dengan kode ilmiah, dan akhirnya terasa seperti buatan atau seperti buang-buang waktu.

Haruskah kita menulis unit test untuk kode penelitian?

David Ketcheson
sumber
2
Ini sedikit pertanyaan terbuka, bukan?
qubyte
2
Seperti semua "aturan", dosis pemikiran kritis selalu berlaku. Tanyakan pada diri Anda apakah rutin tertentu memiliki cara yang jelas untuk diuji unit. Jika tidak, maka unit test tidak masuk akal pada saat itu, atau desain kodenya buruk. Idealnya, satu rutin melakukan satu tugas sebagai independen dari rutinitas lain mungkin, tetapi itu harus ditukar sesekali.
Lagerbaer
Ada beberapa diskusi yang baik dalam nada yang sama tentang pertanyaan tentang stackoverflow .
naught101

Jawaban:

85

Selama bertahun-tahun saya berada di bawah kesalahpahaman bahwa saya tidak punya cukup waktu untuk menulis unit test untuk kode saya. Ketika saya menulis tes, itu adalah hal-hal berat yang membuat saya berpikir bahwa saya seharusnya menulis unit test ketika saya tahu itu diperlukan.

Kemudian saya mulai menggunakan Test Driven Development dan saya menemukan itu sebagai wahyu yang lengkap. Saya sekarang sangat yakin bahwa saya tidak punya waktu untuk tidak menulis tes unit .

Dalam pengalaman saya, dengan mengembangkan dengan pengujian dalam pikiran Anda berakhir dengan antarmuka yang lebih bersih, kelas & modul yang lebih fokus dan umumnya lebih SOLID , kode diuji.

Setiap kali saya bekerja dengan kode lama yang tidak memiliki tes unit dan harus menguji sesuatu secara manual, saya terus berpikir "ini akan jauh lebih cepat jika kode ini sudah memiliki unit test". Setiap kali saya harus mencoba dan menambahkan fungsionalitas unit test ke kode dengan kopling tinggi, saya terus berpikir "ini akan jauh lebih mudah jika telah ditulis dengan cara de-coupled".

Membandingkan dan membedakan dua stasiun percobaan yang saya dukung. Satu telah ada untuk sementara waktu dan memiliki banyak kode warisan, sedangkan yang lainnya relatif baru.

Saat menambahkan fungsionalitas ke lab lama, sering kali turun ke lab dan menghabiskan waktu berjam-jam bekerja melalui implikasi fungsionalitas yang mereka butuhkan dan bagaimana saya dapat menambahkan fungsionalitas itu tanpa mempengaruhi fungsi lainnya. Kode sama sekali tidak diatur untuk memungkinkan pengujian off-line, jadi hampir semuanya harus dikembangkan on-line. Jika saya mencoba mengembangkan secara off-line maka saya akan berakhir dengan lebih banyak objek tiruan daripada yang masuk akal.

Di lab yang lebih baru, saya biasanya dapat menambahkan fungsionalitas dengan mengembangkannya secara off-line di meja saya, mengejek hanya hal-hal yang segera diperlukan, dan kemudian hanya menghabiskan waktu singkat di lab, menambal masalah yang tersisa tidak diambil. -baris.

Untuk kejelasan, dan karena @ naught101 bertanya ...

Saya cenderung bekerja pada kontrol eksperimental dan perangkat lunak akuisisi data, dengan beberapa analisis data ad hoc, sehingga kombinasi TDD dengan kontrol revisi membantu untuk mendokumentasikan perubahan dalam perangkat keras eksperimen yang mendasarinya dan juga perubahan dalam persyaratan pengumpulan data dari waktu ke waktu.

Bahkan dalam situasi mengembangkan kode eksplorasi, saya dapat melihat manfaat yang signifikan dari asumsi yang dikodifikasikan, bersama dengan kemampuan untuk melihat bagaimana asumsi-asumsi tersebut berkembang dari waktu ke waktu.

Mark Booth
sumber
7
Mark, kode macam apa yang kamu bicarakan di sini? Model yang dapat digunakan kembali? Saya menemukan bahwa alasan ini tidak benar-benar berlaku untuk hal-hal seperti kode analisis data eksplorasi, di mana Anda benar-benar harus sering berkeliaran, dan sering kali tidak pernah berharap untuk menggunakan kembali kode di tempat lain.
naught101
35

Kode ilmiah cenderung memiliki konstelasi fungsi yang saling terkait lebih sering daripada kode bisnis yang saya kerjakan, biasanya karena struktur matematika dari masalah. Jadi, saya tidak berpikir unit test untuk fungsi individual sangat efektif. Namun, saya pikir ada kelas unit test yang efektif, dan masih sangat berbeda dari tes seluruh program karena mereka menargetkan fungsionalitas tertentu.

Saya hanya menjelaskan secara singkat apa yang saya maksud dengan tes semacam ini. Pengujian regresi mencari perubahan dalam perilaku yang ada (entah bagaimana divalidasi) ketika perubahan dilakukan pada kode. Pengujian unit menjalankan sepotong kode dan memeriksa apakah ia memberikan output yang diinginkan berdasarkan spesifikasi. Mereka tidak jauh berbeda, karena tes regresi asli adalah tes unit karena saya harus menentukan bahwa output itu valid.

Contoh favorit saya dari uji unit numerik adalah menguji tingkat konvergensi implementasi elemen hingga. Ini jelas tidak sederhana, tetapi dibutuhkan solusi yang diketahui untuk PDE, menjalankan beberapa masalah dengan mengurangi ukuran mesh , dan kemudian menyesuaikan norma kesalahan dengan kurva C h r di mana r adalah tingkat konvergensi. Saya melakukan ini untuk masalah Poisson di PETSc menggunakan Python. Saya tidak mencari perbedaan, seperti dalam regresi, tetapi nilai r khusus untuk elemen yang diberikan.hChrrr

Dua contoh lagi pengujian unit, yang berasal dari PyLith , adalah lokasi titik, yang merupakan fungsi tunggal yang mudah untuk menghasilkan hasil sintetik, dan pembuatan sel kohesif volume nol dalam sebuah mesh, yang melibatkan beberapa fungsi tetapi membahas sepotong terbatas fungsi dalam kode.

Ada banyak tes semacam ini, termasuk tes konservasi dan konsistensi. Operasi tidak jauh berbeda dari regresi (Anda menjalankan tes dan memeriksa output terhadap standar), tetapi output standar berasal dari spesifikasi daripada lari sebelumnya.

Matt Knepley
sumber
4
Wikipedia mengatakan, "Pengujian unit, juga dikenal sebagai pengujian komponen, mengacu pada pengujian yang memverifikasi fungsionalitas bagian kode tertentu, biasanya pada tingkat fungsi." Tes konvergensi dalam kode elemen hingga jelas tidak bisa menjadi unit test karena melibatkan banyak fungsi.
David Ketcheson
Itulah sebabnya saya membuat jelas di bagian atas posting bahwa saya mengambil pandangan luas dari tes unit, dan "biasanya" berarti persis seperti itu.
Matt Knepley
Pertanyaan saya dimaksudkan dalam arti definisi unit test yang lebih luas diterima. Saya sekarang telah membuat ini sepenuhnya eksplisit dalam pertanyaan.
David Ketcheson
Saya telah mengklarifikasi jawaban saya
Matt Knepley
Contoh terakhir Anda relevan dengan apa yang saya maksudkan.
David Ketcheson
28

Sejak saya membaca tentang Test-Driven Development di Code Complete, edisi ke-2 , saya telah menggunakan kerangka pengujian unitsebagai bagian dari strategi pengembangan saya, dan itu secara dramatis meningkatkan produktivitas saya dengan mengurangi jumlah waktu yang saya habiskan untuk debugging karena berbagai tes yang saya tulis bersifat diagnostik. Sebagai manfaat sampingan, saya jauh lebih percaya diri dalam hasil ilmiah saya, dan telah menggunakan unit test saya pada sejumlah kesempatan untuk mempertahankan hasil saya. Jika ada kesalahan dalam tes unit, saya biasanya bisa mengetahui mengapa cukup cepat. Jika aplikasi saya macet dan semua unit test saya lulus, saya melakukan analisis cakupan kode untuk melihat bagian mana dari kode saya yang tidak dijalankan, serta melangkah melalui kode dengan debugger untuk menentukan sumber kesalahan. Lalu saya menulis tes baru untuk memastikan bahwa bug tetap diperbaiki.

Banyak tes yang saya tulis bukan tes unit murni. Didefinisikan dengan ketat, unit test seharusnya menjalankan fungsionalitas dari satu fungsi. Ketika saya dapat dengan mudah menguji satu fungsi menggunakan data tiruan, saya melakukannya. Di lain waktu, saya tidak bisa dengan mudah mengejek data yang saya butuhkan untuk menulis tes yang menjalankan fungsi dari fungsi yang diberikan, jadi saya akan menguji fungsi itu bersama dengan orang lain dalam tes integrasi. Tes integrasimenguji perilaku beberapa fungsi sekaligus. Seperti yang Matt tunjukkan, kode ilmiah sering merupakan rasi fungsi yang saling terkait, tetapi sering kali, fungsi tertentu disebut secara berurutan, dan unit test dapat ditulis untuk menguji output pada langkah-langkah menengah. Misalnya, jika kode produksi saya memanggil lima fungsi secara berurutan, saya akan menulis lima tes. Tes pertama akan memanggil fungsi pertama saja (jadi ini adalah unit test). Kemudian tes kedua akan memanggil fungsi pertama dan kedua, tes ketiga akan memanggil tiga fungsi pertama, dan seterusnya. Bahkan jika saya dapat menulis unit test untuk setiap fungsi tunggal dalam kode saya, saya tetap akan menulis tes integrasi, karena bug dapat muncul ketika berbagai potongan modular dari suatu program digabungkan. Akhirnya, setelah menulis semua tes unit dan tes integrasi, saya pikir saya perlu, saya Saya akan membungkus studi kasus saya dalam unit test dan menggunakannya untuk pengujian regresi, karena saya ingin hasil saya dapat diulang. Jika tidak dapat diulang, dan saya mendapatkan hasil yang berbeda, saya ingin tahu mengapa. Kegagalan tes regresi mungkin bukan masalah nyata, tetapi itu akan memaksa saya untuk mencari tahu apakah hasil baru setidaknya sama dapat dipercaya dengan hasil lama.

Juga bermanfaat bersama dengan pengujian unit adalah analisis kode statis, penghilang memori, dan kompilasi dengan flag peringatan kompiler untuk menangkap kesalahan sederhana dan kode yang tidak digunakan.

Geoff Oxberry
sumber
terkait programer
siamii
Apakah Anda menganggap tes integrasi cukup, atau Anda pikir Anda juga perlu menulis tes unit terpisah?
siamii
Saya akan menulis unit test terpisah di mana pun dimungkinkan dan layak dilakukan. Itu membuat debugging lebih mudah, dan memberlakukan kode decoupled (yang Anda inginkan).
Geoff Oxberry
19

Dalam pengalaman saya, ketika kompleksitas kode penelitian ilmiah meningkat, ada kebutuhan untuk memiliki pendekatan yang sangat modular dalam pemrograman. Ini bisa menyakitkan untuk kode dengan basis besar dan kuno ( f77siapa pun?) Tetapi perlu bergerak maju. Ketika modul dibangun berdasarkan aspek tertentu dari kode (untuk aplikasi CFD, pikirkan Ketentuan Batas atau Termodinamika), pengujian unit sangat berharga untuk memvalidasi implementasi baru dan mengisolasi masalah dan pengembangan perangkat lunak lebih lanjut.

Unit test ini harus satu tingkat di bawah verifikasi kode (dapatkah saya memulihkan solusi analitik persamaan gelombang saya?) Dan 2 tingkat di bawah validasi kode (dapatkah saya memprediksi nilai RMS puncak yang benar dalam aliran pipa turbulen saya), hanya memastikan bahwa pemrograman (adakah argumen yang diteruskan dengan benar, apakah pointer menunjuk ke hal yang benar?) dan "matematika" (subrutin ini menghitung koefisien gesekan. Jika saya memasukkan satu set angka dan menghitung solusinya dengan tangan, apakah rutin menghasilkan sama hasil?) benar. Pada dasarnya naik satu tingkat di atas apa yang bisa dilihat oleh kompiler, yaitu kesalahan sintaksis dasar.

Saya pasti akan merekomendasikannya untuk setidaknya beberapa modul penting dalam aplikasi Anda. Namun, kita harus menyadari bahwa ini sangat membosankan dan menghabiskan waktu jadi kecuali Anda memiliki tenaga manusia yang tidak terbatas, saya tidak akan merekomendasikannya untuk 100% dari kode yang kompleks.

FrenchKheldar
sumber
Apakah Anda memiliki contoh atau kriteria spesifik untuk memilih bagian mana yang akan diuji unit (dan mana yang tidak)?
David Ketcheson
@DavidKetcheson Pengalaman saya dibatasi oleh aplikasi dan bahasa yang kami gunakan. Jadi untuk kode CFD tujuan umum kami dengan sekitar 200 ribu baris sebagian besar F90, kami telah mencoba selama satu atau dua tahun terakhir untuk benar-benar mengisolasi beberapa fungsi kode. Membuat modul dan menggunakannya di seluruh kode tidak mencapai ini sehingga kita harus benar-benar membandingkan modul-modul ini dan secara praktis menjadikannya perpustakaan. Jadi hanya sedikit pernyataan USE dan semua koneksi dengan kode lainnya yang dilakukan melalui panggilan rutin. Rutinitas yang tentu saja bisa Anda sesuaikan, seperti halnya perpustakaan lainnya.
FrenchKheldar
@DavidKetcheson Seperti yang saya katakan dalam jawaban saya, kondisi batas dan termodinamika adalah 2 aspek dari kode kami yang kami kelola untuk benar-benar mengisolasi dan dengan demikian menyatukan semua ini masuk akal. Secara lebih umum, saya akan mulai dengan sesuatu yang kecil dan mencoba melakukannya dengan bersih. Idealnya ini adalah pekerjaan 2 orang. Satu orang menulis rutinitas dan dokumentasi yang menggambarkan antarmuka, orang lain harus menulis unit test, idealnya tanpa melihat kode sumber dan hanya akan melalui deskripsi antarmuka. Dengan begitu niat rutin diuji tetapi saya menyadari ini bukan hal yang mudah untuk diatur.
FrenchKheldar
1
Mengapa tidak menyertakan jenis pengujian perangkat lunak lain (integrasi, sistem) selain pengujian unit? Selain waktu dan biaya, bukankah ini solusi teknis terlengkap? Referensi saya adalah 1 (Bagian 3.4.2) dan 2 (halaman 5). Dengan kata lain, bukankah Kode Sumber harus diuji oleh pengujian perangkat lunak tradisional level 3 ("Level pengujian")?
ximiki
14

Pengujian unit untuk kode ilmiah berguna karena berbagai alasan.

Tiga khususnya adalah:

  • Tes unit membantu orang lain memahami batasan kode Anda. Pada dasarnya, unit test adalah bentuk dokumentasi.

  • Tes unit memeriksa untuk memastikan bahwa satu unit kode mengembalikan hasil yang benar, dan memeriksa untuk memastikan bahwa perilaku suatu program tidak berubah ketika detail dimodifikasi.

  • Menggunakan unit test memudahkan untuk memodulasi kode penelitian Anda. Ini bisa sangat penting jika Anda mulai mencoba menargetkan kode Anda di platform baru, misalnya Anda tertarik untuk memparalelkannya, atau menjalankannya pada mesin GPGPU.

Yang paling penting, tes unit memberi Anda keyakinan bahwa hasil penelitian yang Anda hasilkan menggunakan kode Anda valid dan dapat diverifikasi.

Saya perhatikan bahwa Anda menyebutkan pengujian regresi dalam pertanyaan Anda. Dalam banyak kasus, pengujian regresi dicapai melalui otomatisasi, pelaksanaan rutin unit test dan / atau tes integrasi (yang menguji bahwa potongan-potongan kode bekerja dengan benar ketika digabungkan; dalam komputasi ilmiah, ini sering dilakukan dengan membandingkan keluaran ke data eksperimental atau hasil dari program sebelumnya yang tepercaya). Sepertinya Anda sudah menggunakan tes integrasi atau unit test pada tingkat komponen kompleks besar dengan sukses.

Apa yang akan saya katakan adalah bahwa ketika kode penelitian semakin kompleks, dan bergantung pada kode dan perpustakaan orang lain, penting untuk memahami di mana kesalahan terjadi ketika itu terjadi. Unit testing memungkinkan kesalahan untuk menunjukkan dengan lebih mudah.

Anda dapat menemukan deskripsi, bukti, dan referensi di Bagian 7 "Rencana kesalahan" dari makalah yang saya tulis bersama tentang Praktik Terbaik untuk Komputasi Ilmiah bermanfaat - ini juga memperkenalkan konsep komplementer pemrograman defensif.

Neil Chue Hong
sumber
9

Di kelas deal.II saya mengajarkan bahwa perangkat lunak yang tidak memiliki tes tidak bekerja dengan benar (dan pergi untuk stres bahwa saya sengaja mengatakan " tidak tidak bekerja dengan benar", bukan " mungkin tidak bekerja dengan benar).

Tentu saja saya hidup dengan mantra - begitulah kesepakatannya. Saya telah menjalankan 2.500 tes dengan setiap komit ;-)

Lebih serius, saya pikir Matt sudah mendefinisikan dua kelas tes dengan baik. Kami menulis unit test untuk hal-hal tingkat yang lebih rendah dan itu semacam berkembang secara alami untuk tes regresi untuk hal-hal tingkat yang lebih tinggi. Saya tidak berpikir saya bisa menggambar batas yang jelas yang akan memisahkan pengujian kami ke satu sisi atau yang lain, pasti ada banyak yang menginjak garis di mana seseorang telah melihat output dan menemukan itu sebagian besar masuk akal (unit test?) tanpa harus melihat sedikit keakuratan terakhir (uji regresi?).

Wolfgang Bangerth
sumber
Mengapa Anda mengusulkan hierarki ini (unit untuk yang lebih rendah, regresi untuk yang lebih tinggi) versus tingkat tradisional dalam pengujian perangkat lunak?
ximiki
@ximiki - Saya tidak bermaksud demikian. Saya mengatakan bahwa tes ada pada spektrum yang akan mencakup semua kategori yang tercantum dalam tautan Anda.
Wolfgang Bangerth
8

Iya dan tidak. Tentu saja tidak cocok untuk rutinitas mendasar dari perangkat dasar yang Anda gunakan untuk membuat hidup Anda lebih mudah, seperti rutinitas konversi, pemetaan string, fisika dasar dan matematika, dll. Ketika datang ke kelas perhitungan atau fungsi, mereka biasanya membutuhkan waktu jangka panjang, dan Anda mungkin lebih suka mengujinya sebagai tes fungsional, bukan sebagai unit. Juga, unittest dan sangat menekankan kelas dan entitas yang tingkat dan penggunaannya akan banyak berubah (misalnya untuk tujuan optimasi) atau yang detail internalnya akan diubah karena alasan apa pun. Contoh paling khas adalah kelas yang membungkus matriks besar, dipetakan dari disk.

Stefano Borini
sumber
7

Benar!

Apa, itu tidak cukup untukmu?

Dalam pemrograman ilmiah lebih dari jenis apa pun, kami sedang mengembangkan berdasarkan upaya mencocokkan sistem fisik. Bagaimana Anda tahu jika Anda telah melakukan itu selain dari pengujian? Bahkan sebelum Anda mulai membuat kode, putuskan bagaimana Anda akan menggunakan kode Anda dan buat beberapa contoh proses. Cobalah untuk menangkap setiap kasus tepi yang mungkin. Lakukan dengan cara modular - misalnya, untuk jaringan saraf Anda dapat membuat satu set tes untuk satu neuron dan satu set tes untuk jaringan saraf lengkap. Dengan begitu ketika Anda mulai menulis kode Anda dapat memastikan neuron Anda berfungsi sebelum Anda mulai bekerja di jaringan. Bekerja dalam tahap seperti ini berarti bahwa ketika Anda mengalami masalah Anda hanya memiliki 'tahap' kode yang paling baru untuk diuji, tahap sebelumnya telah diuji.

Plus, setelah Anda memiliki tes, jika Anda perlu menulis ulang kode dalam bahasa yang berbeda (misalnya, mengkonversi ke CUDA), atau bahkan jika Anda baru saja memperbarui, Anda sudah memiliki testcases dan Anda dapat menggunakannya untuk membuat Pastikan kedua versi program Anda bekerja dengan cara yang sama.

Dan
sumber
+1: "Bekerja dalam tahap seperti ini berarti bahwa ketika Anda mengalami masalah Anda hanya memiliki 'tahap' kode yang paling baru untuk diuji, tahap sebelumnya telah diuji."
ximiki
5

Iya.

Gagasan bahwa kode apa pun ditulis tanpa unit test adalah laknat. Kecuali Anda membuktikan kode Anda benar dan kemudian membuktikan buktinya benar = P.

aterrel
sumber
3
... dan kemudian Anda membuktikan bahwa bukti bahwa buktinya benar, dan ... sekarang adalah lubang kelinci yang dalam.
JM
2
Turtles sepanjang jalan membuat Dijkstra bangga!
aterrel
2
Selesaikan saja kasus umum, dan kemudian buktikan bukti Anda sendiri benar! Torus kura-kura!
Aesin
5

Saya akan mendekati pertanyaan ini secara pragmatis daripada dogmatis. Tanyakan kepada diri Anda pertanyaan: "Apa yang bisa salah dalam fungsi X?" Bayangkan apa yang terjadi pada output ketika Anda memasukkan beberapa bug khas ke dalam kode: prefactor yang salah, indeks yang salah, ... Dan kemudian tulis unit test yang mungkin mendeteksi bug semacam itu. Jika untuk fungsi yang diberikan tidak ada cara untuk menulis tes seperti itu tanpa mengulang kode fungsi itu sendiri, maka jangan - tetapi pikirkan tentang tes pada tingkat yang lebih tinggi berikutnya.

Masalah yang jauh lebih penting dengan tes unit (atau bahkan tes apa pun ) dalam kode ilmiah adalah bagaimana menghadapi ketidakpastian aritmatika floating-point. Sejauh yang saya tahu belum ada solusi umum yang baik.

khinsen
sumber
Apakah Anda menguji secara manual atau otomatis menggunakan unit test, Anda memiliki masalah yang sama persis dengan representasi floating point. Saya akan sangat merekomendasikan serangkaian artikel luar biasa Richard Harris di majalah ACCU yang berlebihan .
Mark Booth
"Jika untuk fungsi yang diberikan tidak ada cara untuk menulis tes seperti itu tanpa mengulangi kode fungsi itu sendiri, maka jangan". Bisakah Anda menguraikan? Sebuah contoh akan membuat ini jelas bagi saya.
ximiki
5

Saya merasa kasihan pada Tangurena - di sekitar sini, mantra adalah "Kode yang belum diuji adalah kode yang rusak" dan itu datang dari bos. Daripada mengulangi semua alasan bagus untuk melakukan pengujian unit, saya hanya ingin menambahkan beberapa spesifik.

  • Penggunaan memori harus diuji. Setiap fungsi yang mengalokasikan memori harus diuji memastikan bahwa fungsi yang menyimpan dan mengambil data ke dalam memori itu melakukan hal yang benar. Ini bahkan lebih penting di dunia GPU.
  • Sementara disebutkan secara singkat sebelumnya, pengujian kasus tepi sangat penting. Pikirkan tes ini dengan cara yang sama seperti Anda menguji hasil perhitungan apa pun. Pastikan kode berperilaku di tepi dan gagal dengan anggun (namun Anda mendefinisikannya dalam simulasi Anda) ketika parameter input atau data berada di luar batas yang dapat diterima. Pemikiran yang terlibat dalam penulisan tes semacam ini membantu mempertajam pekerjaan Anda dan mungkin menjadi salah satu alasan mengapa Anda jarang menemukan seseorang yang memiliki tes unit tertulis tetapi tidak menganggap prosesnya bermanfaat.
  • Gunakan kerangka uji (seperti yang disebutkan oleh Geoff yang memberikan tautan bagus). Saya telah menggunakan kerangka uji BOOST dalam hubungannya dengan sistem CTest CMake dan dapat merekomendasikannya sebagai cara mudah untuk dengan cepat menulis unit test (serta tes validasi dan regresi).
pengguna69
sumber
+1: "Pastikan kode berperilaku di tepi dan gagal dengan anggun (namun Anda mendefinisikannya dalam simulasi Anda) ketika parameter input atau data berada di luar batas yang dapat diterima."
ximiki
5

Saya telah menggunakan pengujian unit untuk efek yang baik pada beberapa kode skala kecil (yaitu programmer tunggal), termasuk versi ketiga dari kode analisis disertasi saya dalam fisika partikel.

Dua versi pertama telah runtuh karena beratnya sendiri dan multiplikasi interkoneksi.

Yang lain telah menulis bahwa interaksi antar modul seringkali merupakan tempat di mana koding ilmiah terputus, dan mereka benar tentang hal itu. Tapi itu jauh lebih mudah untuk mendiagnosa orang masalah ketika Anda dapat menunjukkan secara meyakinkan bahwa setiap modul adalah melakukan apa yang dimaksudkan untuk melakukan.

dmckee
sumber
3

Pendekatan yang sedikit berbeda yang saya gunakan ketika mengembangkan pemecah kimia (untuk domain geologi yang kompleks) adalah apa yang Anda sebut Unit Testing oleh Copy and Paste Snippet .

Membangun test harness untuk kode asli yang tertanam dalam modeller sistem kimia besar tidak layak dalam jangka waktu.

Namun, saya dapat mengerjakan set potongan yang semakin kompleks yang menunjukkan bagaimana pengurai (Boost Spirit) untuk formula kimia bekerja, sebagai unit test untuk ekspresi yang berbeda.

Tes unit terakhir, paling kompleks sangat dekat dengan kode yang diperlukan dalam sistem, tanpa harus mengubah kode itu agar dapat dipermainkan. Dengan demikian saya dapat menyalin seluruh kode unit yang saya uji.

Apa yang menjadikan ini lebih dari sekadar latihan pembelajaran dan rangkaian regresi sejati adalah dua faktor - unit test disimpan di sumber utama dan dijalankan sebagai bagian dari tes lain untuk aplikasi itu (dan ya, mereka memang mengambil efek samping dari Boost Semangat berubah 2 tahun kemudian) - karena kode yang disalin dan disisipkan secara minimal dimodifikasi dalam aplikasi nyata, itu bisa memiliki komentar merujuk kembali ke unit test untuk membantu seseorang tetap selaras.

Andy Dent
sumber
2

Untuk basis kode yang lebih besar, tes (tidak harus unit test) untuk hal-hal tingkat tinggi berguna. Tes unit untuk beberapa algoritma sederhana juga berguna untuk memastikan kode Anda tidak masuk akal karena fungsi pembantu Anda menggunakan sinalih-alihcos .

Tetapi untuk keseluruhan kode penelitian sangat sulit untuk menulis dan mempertahankan tes. Algoritma cenderung besar tanpa hasil antara yang berarti yang dapat memiliki tes yang jelas dan sering membutuhkan waktu lama untuk dijalankan sebelum ada hasilnya. Tentu saja Anda dapat menguji terhadap referensi berjalan yang memiliki hasil bagus, tetapi ini bukan tes yang baik dalam arti unit test.

Hasil seringkali merupakan perkiraan solusi yang sebenarnya. Meskipun Anda dapat menguji fungsi-fungsi sederhana Anda jika akurat hingga beberapa epsilon, akan sangat sulit untuk memverifikasi apakah beberapa hasil mesh benar atau tidak, yang dievaluasi dengan inspeksi visual oleh pengguna (Anda) sebelumnya.

Dalam kasus seperti itu, tes otomatis seringkali memiliki rasio biaya / manfaat yang terlalu tinggi. Saya merekomendasikan sesuatu yang lebih baik: Menulis program pengujian. Sebagai contoh saya menulis skrip python ukuran sedang untuk membuat data tentang hasil, seperti histogram ukuran tepi dan sudut mesh, area segitiga terbesar dan terkecil serta perbandingannya, dll.

Saya dapat menggunakannya untuk mengevaluasi jerat input dan output selama operasi normal dan menggunakannya untuk melakukan pemeriksaan kewarasan setelah saya mengubah algoritme. Ketika saya mengubah algoritme, saya tidak selalu tahu apakah hasil yang baru lebih baik, karena seringkali tidak ada ukuran absolut yang merupakan perkiraan yang terbaik. Tetapi dengan menghasilkan metrik seperti itu, saya dapat mengetahui beberapa faktor apa yang lebih baik seperti "Varian baru pada akhirnya memiliki rasio sudut yang lebih baik tetapi tingkat konvergensi yang lebih buruk".

allo
sumber