Saya seorang programmer yang agak defensif dan penggemar berat Kontrak Kode Microsoft.
Sekarang saya tidak bisa selalu menggunakan C # dan dalam kebanyakan bahasa satu-satunya alat yang saya miliki adalah pernyataan. Jadi saya biasanya berakhir dengan kode seperti ini:
class
{
function()
{
checkInvariants();
assert(/* requirement */);
try
{
/* implementation */
}
catch(...)
{
assert(/* exceptional ensures */);
}
finally
{
assert(/* ensures */);
checkInvariants();
}
}
void checkInvariants()
{
assert(/* invariant */);
}
}
Namun, paradigma ini (atau apa pun namanya) menyebabkan banyak kode berantakan.
Saya sudah mulai bertanya-tanya apakah itu benar-benar sepadan dengan usaha dan apakah unit test yang tepat sudah akan membahas ini?
testing
code-contracts
ronag
sumber
sumber
Jawaban:
Saya tidak berpikir Anda harus menganggapnya sebagai "vs".
Seperti disebutkan dalam komentar oleh @Giorgio, kontrak kode adalah untuk memeriksa invarian (dalam lingkungan produksi) dan unit test memastikan bahwa kode Anda berfungsi seperti yang diharapkan ketika persyaratan tersebut dipenuhi.
sumber
Kontrak membantu Anda dengan setidaknya satu hal yang tidak dilakukan unit test. Saat Anda mengembangkan API publik, Anda tidak dapat menguji bagaimana orang menggunakan kode Anda. Namun Anda masih dapat menentukan kontrak untuk metode Anda.
Saya pribadi akan seketat ini tentang kontrak hanya ketika berhadapan dengan API modul publik. Dalam banyak kasus lain, ini mungkin tidak sepadan dengan usaha (dan Anda dapat menggunakan tes unit sebagai gantinya), tetapi ini hanya pendapat saya.
Itu tidak berarti saya menyarankan untuk tidak memikirkan kontrak dalam kasus-kasus itu. Saya selalu memikirkan mereka. Saya hanya tidak berpikir perlu untuk selalu secara eksplisit kode mereka.
sumber
Seperti telah disebutkan Kontrak dan unit test memiliki tujuan berbeda.
Kontrak adalah tentang pemrograman defensif untuk memastikan bahwa prasyarat terpenuhi, kode dipanggil dengan parameter yang benar, dll.
Tes unit untuk memastikan kode itu berfungsi, dalam skenario yang berbeda. Ini seperti 'spesifikasi dengan gigi'.
Asserts bagus mereka membuat kode kuat. Namun, jika Anda khawatir akan menambah banyak kode, Anda mungkin juga ingin menambahkan breakpoint bersyarat di beberapa tempat selama proses debug dan mengurangi jumlah Assert.
sumber
Apa pun yang Anda miliki di checkVariants () panggilan Anda dapat dilakukan dari pengujian, seberapa banyak upaya yang sebenarnya mungkin tergantung banyak hal (dependensi eksternal, tingkat penggandaan, dll.) Tetapi itu akan membersihkan kode dari satu sudut pandang. Bagaimana testable berbasis kode dikembangkan terhadap asersi tanpa refactoring saya tidak yakin.
Saya setuju dengan @duros, ini tidak boleh dianggap sebagai pendekatan yang eksklusif atau bersaing. Bahkan dalam lingkungan TDD Anda bahkan bisa berdebat bahwa pernyataan 'persyaratan' akan perlu memiliki tes :).
Akan tetapi, JANGAN membuat kode lebih kuat kecuali Anda benar-benar melakukan sesuatu untuk memperbaiki cek yang gagal, mereka hanya menghentikan data yang rusak atau serupa, biasanya dengan membatalkan pemrosesan pada tanda pertama masalah.
Suatu solusi yang digerakkan oleh tes / teruji dengan baik biasanya sudah memikirkan dan / atau menemukan banyak sumber / alasan input dan output yang buruk sementara mengembangkan komponen yang berinteraksi dan sudah berurusan dengan mereka lebih dekat ke sumber masalah.
Jika sumber Anda adalah eksternal dan Anda tidak memiliki kontrol atasnya maka untuk menghindari mengacaukan kode Anda berurusan dengan masalah kode lain, Anda mungkin mempertimbangkan untuk menerapkan semacam komponen pembersihan-data / pernyataan di antara sumber dan komponen Anda dan meletakkan cek Anda di sana .
Saya juga ingin tahu bahasa apa yang Anda gunakan yang tidak memiliki semacam xUnit atau pustaka pengujian lain yang telah dikembangkan seseorang, saya pikir ada cukup banyak sesuatu untuk semuanya akhir-akhir ini?
sumber
Selain pengujian unit dan kontrak kode, saya hanya berpikir saya akan menyoroti aspek lain, yang merupakan nilai dalam mendefinisikan antarmuka Anda sehingga Anda menghilangkan atau mengurangi kemungkinan memanggil kode Anda secara salah.
Ini tidak selalu mudah atau mungkin, tetapi pasti patut bertanya pada diri sendiri pertanyaan, "Bisakah saya membuat kode ini lebih mudah?"
Anders Hejlsberg, pencipta C #, mengatakan bahwa salah satu kesalahan terbesar dalam C # tidak termasuk jenis referensi yang tidak dapat dibatalkan. Itu salah satu alasan utama begitu banyak kekacauan kode penjaga diperlukan.
Namun, refactoring untuk hanya memiliki jumlah kode penjaga yang diperlukan dan memadai membuat, menurut pengalaman saya, lebih mudah digunakan dan dipelihara kode.
Setuju dengan @duros untuk sisanya.
sumber
Lakukan keduanya, tetapi buat beberapa metode pembantu statis untuk mengklarifikasi niat Anda. Inilah yang dilakukan Google untuk Java, periksa code.google.com/p/guava-libraries/wiki/PreconditionsExplained
sumber