Apakah pengujian atau unit test lebih penting?

51

Baik assert dan unit test berfungsi sebagai dokumentasi untuk basis kode, dan sarana untuk menemukan bug. Perbedaan utama adalah bahwa fungsi menegaskan sebagai kewarasan memeriksa dan melihat input nyata, sedangkan tes unit berjalan pada input simulasi spesifik dan merupakan tes terhadap "jawaban benar" tunggal yang jelas. Apa manfaat relatif dari menggunakan tes vs unit test sebagai alat utama memverifikasi kebenaran? Menurut Anda, mana yang harus lebih ditekankan?

dsimcha
sumber
4
Saya sangat menyukai ide ini ... sangat banyak sehingga saya membuat topik tugas untuk pengujian perangkat lunak dan kursus jaminan kualitas. :-)
Macneil
Pertanyaan lain adalah: apakah Anda harus menguji unit Anda menegaskan? ;)
mojuba

Jawaban:

43

Sisipan berguna untuk memberi tahu Anda tentang keadaan internal program . Misalnya, bahwa struktur data Anda memiliki status yang valid, misalnya, bahwa Timestruktur data tidak memiliki nilai 25:61:61. Kondisi yang diperiksa dengan menegaskan adalah:

  • Prasyarat, yang memastikan bahwa penelepon menjaga kontraknya,

  • Postconditions, yang memastikan bahwa callee menyimpan kontraknya, dan

  • Invarian, yang memastikan bahwa struktur data selalu memiliki beberapa properti setelah fungsi kembali. Invarian adalah suatu kondisi yang merupakan prasyarat dan postkondisi.

Tes unit berguna untuk memberi tahu Anda tentang perilaku eksternal modul . Anda Stackmungkin memiliki status yang konsisten setelah push()metode dipanggil, tetapi jika ukuran tumpukan tidak bertambah tiga setelah disebut tiga kali, maka itu adalah kesalahan. (Misalnya, kasus sepele di mana push()implementasi yang salah hanya memeriksa pernyataan dan keluar.)

Sebenarnya, perbedaan utama antara tes menegaskan dan unit adalah tes unit memiliki data uji (nilai untuk menjalankan program), sedangkan menegaskan tidak. Artinya, Anda dapat menjalankan tes unit Anda secara otomatis, sementara Anda tidak dapat mengatakan hal yang sama untuk pernyataan. Demi diskusi ini, saya berasumsi bahwa Anda berbicara tentang mengeksekusi program dalam konteks tes fungsi tingkat tinggi (yang menjalankan seluruh program, dan tidak menggerakkan modul seperti tes unit). Jika Anda tidak berbicara tentang tes fungsi otomatis sebagai sarana untuk "melihat input nyata", maka jelas nilainya terletak pada otomatisasi, dan dengan demikian unit test akan menang. Jika Anda membicarakan hal ini dalam konteks pengujian fungsi (otomatis), lihat di bawah.

Mungkin ada beberapa tumpang tindih dalam apa yang sedang diuji. Sebagai contoh, Stackpostcondition sebuah sebenarnya dapat menyatakan bahwa ukuran stack meningkat satu. Tetapi ada batas untuk apa yang dapat dilakukan dalam pernyataan itu: Haruskah itu juga memeriksa bahwa elemen atas adalah apa yang baru saja ditambahkan?

Untuk keduanya, tujuannya adalah untuk meningkatkan kualitas. Untuk pengujian unit, tujuannya adalah menemukan bug. Untuk pernyataan, tujuannya adalah untuk mempermudah debugging dengan mengamati status program yang tidak valid segera setelah terjadi.

Perhatikan bahwa tidak ada teknik yang memverifikasi kebenaran. Bahkan, jika Anda melakukan pengujian unit dengan tujuan untuk memverifikasi program itu benar, Anda kemungkinan akan datang dengan tes yang tidak menarik yang Anda tahu akan berhasil. Ini adalah efek psikologis: Anda akan melakukan apa pun untuk memenuhi tujuan Anda. Jika tujuan Anda adalah menemukan bug, aktivitas Anda akan mencerminkan hal itu.

Keduanya penting, dan memiliki tujuan masing-masing.

[Sebagai catatan terakhir tentang pernyataan: Untuk mendapatkan nilai maksimal, Anda harus menggunakannya di semua titik kritis dalam program Anda, dan bukan beberapa fungsi utama. Jika tidak, sumber asli masalah mungkin telah ditutup dan sulit dideteksi tanpa berjam-jam melakukan debugging.]

Macneil
sumber
7

Saat berbicara tentang asersi, ingatlah bahwa asersi tersebut dapat dimatikan dengan cepat.

Contoh pernyataan yang sangat buruk:

char *c = malloc(1024);
assert(c != NULL);

Kenapa ini buruk? Karena tidak ada pengecekan kesalahan yang dilakukan jika pernyataan dilewati karena sesuatu seperti NDEBUG didefinisikan.

Tes unit akan (kemungkinan) hanya memisahkan pada kode di atas. Tentu, itu melakukan tugasnya dengan memberi tahu Anda bahwa ada yang salah, atau bukan? Seberapa besar kemungkinan malloc()gagal dalam ujian?

Pernyataan adalah untuk tujuan debugging ketika seorang programmer perlu menyiratkan bahwa tidak ada kejadian 'normal' yang akan menyebabkan pernyataan tersebut untuk menyala. malloc()gagal adalah, memang peristiwa yang normal, dengan demikian tidak boleh ditegaskan.

Ada banyak kasus lain di mana pernyataan digunakan alih-alih secara memadai menangani hal-hal yang mungkin salah. Inilah sebabnya mengapa pernyataan mendapatkan reputasi buruk, dan mengapa bahasa seperti Go tidak memasukkannya.

Tes unit dirancang untuk memberi tahu Anda ketika sesuatu yang Anda ubah merusak sesuatu yang lain. Mereka dirancang untuk menghemat (dalam banyak kasus) akan melalui setiap fitur dari program ini (Namun, penguji yang penting untuk rilis) setiap kali Anda membuat sebuah build.

Sebenarnya tidak ada korelasi yang jelas di antara keduanya, selain keduanya memberi tahu Anda bahwa ada yang salah. Pikirkan penegasan sebagai breakpoint dalam sesuatu yang sedang Anda kerjakan, tanpa harus menggunakan debugger. Pikirkan unit test sebagai sesuatu yang memberi tahu Anda jika Anda memecahkan sesuatu yang tidak Anda kerjakan.

Pos Tim
sumber
3
Itu sebabnya pernyataan untuk selalu dianggap sebagai pernyataan yang benar, bukan pengujian kesalahan.
Dominique McDonnell
@DominicMcDonnell Baiklah, pernyataan 'harus benar'. Aku kadang-kadang menegaskan untuk berkeliling kebiasaan compiler, seperti versi tertentu dari gcc yang memiliki abs kereta () dibangun di. Yang penting untuk diingat adalah produksi membangun harus memiliki mereka dimatikan pula .
Tim Post
Dan di sini saya pikir kode produksi adalah tempat yang membutuhkan menegaskan yang paling , karena di produksi di mana Anda akan mendapatkan input yang Anda tidak berpikir mungkin. Produksi adalah tempat yang mengusir semua bug tersulit.
Frank Shearar
@ Frank Shearar, sangat benar. Anda masih harus gagal dalam kondisi kesalahan terdeteksi paling awal dalam produksi. Tentu saja para pengguna akan mengeluh, tetapi itulah satu-satunya cara Anda akan memastikan bahwa bug akan diperbaiki. Dan jauh lebih baik untuk mendapatkan bla adalah 0 daripada pengecualian memori untuk dereferencing null beberapa panggilan fungsi nanti.
Dominique McDonnell
mengapa tidak lebih baik untuk menangani masalah yang khas tetapi sering tidak umum (di mata pengguna) daripada menyatakan bahwa hal itu seharusnya tidak pernah terjadi? Saya gagal menyadari kebijaksanaan ini. Tentu, nyatakan bahwa generator utama mengembalikan yang prima, yang membutuhkan sedikit kerja ekstra, yang diharapkan dalam debug build. Menegaskan sesuatu yang secara asli dapat diuji oleh suatu bahasa adalah adil, baik, bodoh. Tidak membungkus tes-tes itu di saklar lain yang dapat dimatikan beberapa bulan setelah rilis, bahkan lebih bodoh.
Tim Post
5

Keduanya adalah alat yang digunakan untuk membantu meningkatkan kualitas keseluruhan sistem yang Anda bangun. Banyak tergantung pada bahasa yang Anda gunakan, jenis aplikasi yang Anda buat, dan di mana waktu Anda dihabiskan. Belum lagi Anda memiliki beberapa aliran pemikiran tentang hal itu.

Untuk memulainya, jika Anda menggunakan bahasa tanpa assertkata kunci, Anda tidak bisa menggunakan kata keterangan (setidaknya tidak dengan cara kita berbicara di sini). Untuk waktu yang lama, Java tidak memiliki assertkata kunci, dan sejumlah bahasa masih belum. Unit testing kemudian menjadi sedikit lebih penting. Dalam beberapa bahasa pernyataan hanya dijalankan ketika bendera diatur (lagi dengan Java di sini). Ketika perlindungan tidak selalu ada, itu bukan fitur yang sangat berguna.

Ada aliran pemikiran yang mengatakan jika Anda "menegaskan" sesuatu, Anda mungkin juga menulis blok pengecualian if/ throwbermakna. Proses pemikiran ini berasal dari banyak pernyataan yang ditempatkan di awal metode untuk memastikan semua nilai terikat. Menguji prasyarat Anda adalah bagian yang sangat penting untuk mendapatkan kondisi pascakemudian yang diharapkan.

Pengujian unit adalah kode tambahan yang harus ditulis dan dipelihara. Bagi banyak orang ini adalah kelemahan. Namun, dengan pemotongan kerangka kerja unit test saat ini di luar sana, Anda dapat menghasilkan sejumlah besar kondisi pengujian dengan kode yang relatif sedikit. Tes parameter dan "teori" akan melakukan tes yang sama dengan sejumlah besar sampel data yang dapat mengungkap beberapa bug yang sulit ditemukan.

Saya pribadi menemukan saya mendapatkan lebih banyak jarak tempuh dengan pengujian unit daripada percikan, tetapi itu karena platform yang saya kembangkan pada sebagian besar waktu (Java / C #). Bahasa lain memiliki dukungan pernyataan yang lebih kuat, dan bahkan "Desain dengan Kontrak" (lihat di bawah) untuk memberikan lebih banyak jaminan. Jika saya bekerja dengan salah satu bahasa ini, saya mungkin menggunakan DBC lebih dari pengujian unit.

http://en.wikipedia.org/wiki/Design_by_contract#Languages_with_native_support

Berin Loritsch
sumber