Semua tes unit dalam satu executable, atau membaginya?

12

Saat menulis tes untuk satu perangkat lunak, katakan perpustakaan, apakah Anda lebih suka mengkompilasi semua tes unit menjadi satu, atau memisahkannya menjadi beberapa yang dapat dieksekusi?

Alasan saya bertanya adalah karena saya saat ini menggunakan CUnit untuk menguji perpustakaan yang sedang saya kerjakan. Pengujian dibagi menjadi beberapa suite terpisah yang dikompilasi menjadi satu yang dapat dieksekusi lengkap dengan hasil cetak untuk kegagalan. Sekarang, sistem build untuk perpustakaan itu adalah CMake (yang, terlepas dari namanya, tidak ada hubungannya dengan CUnit), yang dilengkapi dengan kerangka pengujian sendiri, CTest . CTest memungkinkan saya untuk mendaftar daftar yang dapat dieksekusi yang berfungsi sebagai tes.

Saya sedang mempertimbangkan apakah akan menggunakan CTest untuk menjalankan pengujian otomatis. Namun, ini akan mengharuskan saya untuk membagi tes yang saya tulis sejauh ini menjadi target kompilasi yang terpisah. Kalau tidak, saya tidak bisa benar-benar memanfaatkan beberapa fitur canggih CTests, seperti tes yang dijalankan secara selektif.

Saya menyadari ini lebih merupakan pertanyaan tentang alat apa yang digunakan dan penanganan serta konvensi mereka, tetapi selain itu, adakah alasan lain untuk memilih satu pengujian yang dapat dieksekusi daripada yang terpisah? Atau sebaliknya?

Benjamin Kloster
sumber
Pisahkan mereka menjadi executable yang terpisah berdasarkan kelas. Setiap kelas harus memiliki unit test sendiri kecuali kelas tidak unit dapat diuji dan dengan demikian perlu diuji oleh kelas lain secara tidak langsung.
Brian
1
Jika Anda memiliki perpustakaan besar dengan ratusan kelas, masing-masing dengan unit test, waktu build jauh lebih lama jika Anda membuat biner lengkap untuk masing-masing, dibandingkan dengan satu (atau beberapa) biner besar. Juga, itu banyak makefile untuk dikelola, masing-masing dengan garis tautan individual.
JBRWilkinson
Tidak sebesar itu. Kurang dari 20 modul. Saya juga dapat mengkompilasi mereka semua dengan flag yang sama, sehingga CMake dapat menghasilkan Makefiles tanpa banyak pekerjaan di pihak saya.
Benjamin Kloster

Jawaban:

5

Saya suka melakukan pengujian otomatis dalam biner individual, atau setidaknya mengelompok per grup "milik bersama", dan kemudian memanggil mereka dari skrip shell sederhana (di mana kode keluar bukan nol menandakan kegagalan, dan output pada stderr dapat ditangkap untuk merekam penjelasan). Dengan cara ini, saya mempertahankan fleksibilitas penuh pada pengujian - Saya dapat menjalankan tes individu langsung dari baris perintah, saya dapat membuat semua jenis skrip mewah jika saya mau, saya dapat memesan ulang sesuai keinginan tanpa mengkompilasi ulang apa pun, dll.

Tetapi yang lebih penting, ini juga memungkinkan saya untuk memasukkan tes yang ditulis dalam bahasa yang berbeda atau menggunakan alat bantu yang berbeda dalam proses yang sama. Sebagai contoh, tes unit yang saya tulis kemungkinan besar dalam bahasa utama proyek, dan menjalankannya adalah masalah membangun dan memanggil binari; tapi saya juga ingin menguji database saya, dan saya mungkin ingin memberi makan skrip SQL langsung ke database untuk ini; Saya mungkin ingin menjalankan beberapa alat analisis kode statis pada kode saya (bahkan jika itu hanya semacam linter). Saya mungkin ingin menjalankan HTML statis saya melalui pemeriksa validitas. Saya bisa menjalankan grepperintah di atas basis kode untuk memeriksa konstruksi yang mencurigakan, pelanggaran gaya pengkodean, atau kata kunci "bendera merah". Kemungkinannya tidak terbatas - jika dapat dijalankan dari baris perintah dan mematuhi "status keluar nol berarti OK", saya dapat menggunakannya.

tammmer
sumber
Argumen agnostik bahasa adalah poin yang sangat bagus, karena saya berencana mengimplementasikan python bindings untuk library di ujung jalan. Terima kasih!
Benjamin Kloster
@tdammers: kerangka pengujian tertentu?
JBRWilkinson
@ JBRWilkinson: Hanya skrip shell 30-baris. Untuk sebagian besar bahasa yang saya gunakan, saya memiliki sedikit perpustakaan di sekitar untuk tugas pengujian umum seperti menjalankan fungsi, membandingkan hasilnya dengan nilai yang diharapkan, dan melempar ketika mereka tidak cocok. Tetapi setiap kerangka pengujian unit tertentu dapat dengan mudah diintegrasikan ke dalam "sistem meta" seperti itu, asalkan dapat berjalan dari baris perintah dan menandakan keberhasilan / kegagalan melalui status keluarnya.
tdammers
2

Saya cenderung memiliki satu perpustakaan untuk pengujian unit satu aplikasi (atau untuk paket perpustakaan yang umum dibagikan). Di dalam pustaka itu, saya mencoba untuk mereplikasi atau memperkirakan ruang nama dari objek yang diuji untuk perlengkapan tes (kebanyakan saya menggunakan NUnit). Ini menyederhanakan kompilasi, seperti dalam. NET ada overhead yang melekat dalam membangun setiap biner yang akan meningkatkan waktu pembangunan solusi 20-proyek dibandingkan dengan solusi 10-proyek dengan LOC yang sama. Binari uji tidak didistribusikan, jadi setiap organisasi pengujian ke biner adalah untuk kenyamanan Anda sendiri, dan saya biasanya menemukan bahwa YAGNI berlaku di sini di mana saja.

Sekarang, saya biasanya tidak memiliki pertimbangan yang dimiliki oleh tdammers; kode saya hampir semuanya dalam satu bahasa, dan setiap tes yang melibatkan string SQL bukan merupakan unit test (kecuali jika Anda menguji bahwa seorang pembuat permintaan mengembalikan string SQL yang diharapkan diberikan kriteria tertentu), dan saya hampir tidak pernah menguji unit yang sebenarnya UI (dalam banyak situasi itu tidak mungkin). Saya juga menggunakan pustaka pengujian unit yang diterima dengan baik oleh alat pihak ketiga seperti build-bots dan IDE plugins, dan setiap kekhawatiran menjalankan tes individu, suite parsial dll sangat minim.

KeithS
sumber
1
Soal budaya, saya kira - dalam lingkungan .NET, saya mungkin akan beralasan seperti Anda.
tdammers