Mengapa tidak menguji bahasa sebagai fitur yang didukung di tingkat sintaksis?

37

Anda dapat menemukan daftar blog, artikel, dan situs web tanpa akhir yang mempromosikan manfaat unit yang menguji kode sumber Anda. Hampir dijamin bahwa pengembang yang memprogram kompiler untuk Java, C ++, C # dan bahasa yang diketik lainnya menggunakan pengujian unit untuk memverifikasi pekerjaan mereka.

Jadi mengapa, terlepas dari popularitasnya, apakah pengujian absen dari sintaksis bahasa-bahasa ini?

Microsoft memperkenalkan LINQ ke C # , jadi mengapa mereka tidak menambahkan pengujian?

Saya tidak ingin memprediksi perubahan bahasa apa yang akan terjadi, tetapi untuk mengklarifikasi mengapa mereka tidak ada sejak awal.

Sebagai contoh: Kita tahu bahwa Anda dapat menulis sebuah forloop tanpa sintaks dari forpernyataan tersebut. Anda bisa menggunakan whileatau if/ gotopernyataan. Seseorang memutuskan sebuah forpernyataan lebih efisien dan memperkenalkannya ke dalam bahasa.

Mengapa pengujian tidak mengikuti evolusi bahasa pemrograman yang sama?

Reactgular
sumber
24
Apakah benar-benar lebih baik untuk membuat spesifikasi bahasa lebih kompleks dengan menambahkan sintaks, daripada merancang bahasa dengan aturan sederhana yang dapat dengan mudah diperluas dengan cara yang umum?
KChaloux
6
Apa yang Anda maksud dengan "di level sintaksis"? Apakah Anda memiliki detail / ide tentang bagaimana itu akan diterapkan?
SJuan76
21
Bisakah Anda memberikan contoh pseudo-code pengujian sebagai fitur yang didukung sintaksis? Saya ingin tahu seperti apa kira-kira menurut Anda.
FrustratedWithFormsDesigner
12
@FrustratedWithFormsDesigner Lihat bahasa D untuk contoh.
Doval
4
Bahasa lain dengan fitur pengujian unit bawaan adalah Rust.
Sebastian Redl

Jawaban:

36

Seperti banyak hal, pengujian unit paling baik didukung di tingkat perpustakaan, bukan di tingkat bahasa. Secara khusus, C # memiliki banyak pustaka Pengujian Unit yang tersedia, serta hal-hal yang asli seperti .NET Framework Microsoft.VisualStudio.TestTools.UnitTesting.

Setiap perpustakaan Unit Pengujian memiliki filosofi dan sintaksis pengujian yang agak berbeda. Semua hal dianggap sama, lebih banyak pilihan lebih baik daripada kurang. Jika pengujian unit dimasukkan ke dalam bahasa, Anda akan dikunci ke dalam pilihan perancang bahasa, atau Anda akan menggunakan ... perpustakaan, dan menghindari fitur pengujian bahasa sama sekali.

Contohnya

  • Nunit - Tujuan umum, kerangka pengujian unit yang dirancang secara idiomatis yang memanfaatkan fitur bahasa C # sepenuhnya.

  • Moq - Kerangka mengejek yang memanfaatkan sepenuhnya ekspresi lambda dan pohon ekspresi, tanpa metafora rekaman / pemutaran.

Ada banyak pilihan lain. Perpustakaan seperti Microsoft Fakes dapat membuat "shims ..." mock yang tidak mengharuskan Anda untuk menulis kelas menggunakan antarmuka atau metode virtual.

Linq bukan fitur bahasa (meskipun namanya)

Linq adalah fitur perpustakaan. Kami mendapat banyak fitur baru dalam bahasa C # itu sendiri secara gratis, seperti ekspresi lambda dan metode ekstensi, tetapi implementasi sebenarnya dari Linq ada dalam .NET Framework.

Ada beberapa gula sintaksis yang ditambahkan ke C # untuk membuat pernyataan linq lebih bersih, tetapi gula itu tidak diperlukan untuk menggunakan linq.

Robert Harvey
sumber
1
Saya setuju dengan poin bahwa LINQ bukan fitur bahasa tetapi untuk membuat LINQ terjadi perlu ada beberapa fitur bahasa yang mendasarinya terjadi - terutama generik dan tipe dinamis.
Wyatt Barnett
@ WyattBarnett: Ya, dan hal yang sama berlaku untuk pengujian unit mudah - seperti refleksi dan atribut.
Doc Brown
8
LINQ membutuhkan lambda dan pohon ekspresi. Generik sudah ada di C # (dan .Net secara umum, mereka ada di CLR), dan dinamika tidak ada hubungannya dengan LINQ; Anda dapat melakukan LINQ tanpa dinamis.
Arthur van Leeuwen
Perl's DBIx :: Class adalah contoh fungsionalitas seperti LINQ yang diimplementasikan lebih dari 10 tahun setelah semua fitur yang diperlukan untuk mengimplementasikannya telah menggunakan bahasa.
Slebetman
2
@ Carson63000 Saya pikir maksud Anda jenis anonim dalam kombinasi dengan varkata kunci :)
M.Mimpen
21

Ada banyak alasan. Eric Lippert telah berkali-kali menyatakan bahwa alasannya feature Xtidak ada dalam C # adalah karena itu tidak sesuai dengan anggaran mereka. Perancang bahasa tidak memiliki waktu atau uang yang tidak terbatas untuk mengimplementasikan berbagai hal, dan setiap fitur baru memiliki biaya perawatan yang terkait dengannya. Menjaga bahasa sekecil mungkin tidak hanya lebih mudah bagi perancang bahasa - itu juga lebih mudah bagi siapa pun yang menulis implementasi dan alat alternatif (misalnya IDE). Selain itu, ketika sesuatu diimplementasikan dalam hal bahasa daripada bagian dari itu, Anda mendapatkan portabilitas gratis. Jika pengujian unit diterapkan sebagai pustaka, Anda hanya perlu menulisnya sekali dan itu akan berhasil dalam implementasi bahasa yang sesuai.

Perlu dicatat bahwa D memang memiliki dukungan tingkat sintaks untuk pengujian unit . Saya tidak tahu mengapa mereka memutuskan untuk melemparkan itu, tetapi perlu dicatat bahwa D dimaksudkan untuk menjadi "bahasa pemrograman sistem tingkat tinggi". Para perancang menginginkannya menjadi layak untuk jenis kode C ++ tingkat rendah yang tidak aman, secara tradisional telah digunakan, dan kesalahan dalam kode tidak aman sangat mahal - perilaku yang tidak terdefinisi. Jadi saya kira masuk akal bagi mereka untuk melakukan upaya ekstra pada apa pun yang membantu Anda memverifikasi bahwa beberapa kode tidak aman berfungsi. Misalnya, Anda dapat memastikan bahwa hanya modul tepercaya tertentu yang dapat melakukan operasi yang tidak aman seperti akses larik yang tidak dicentang atau aritmatika penunjuk.

Pengembangan cepat juga merupakan prioritas bagi mereka, sangat banyak sehingga mereka menjadikannya tujuan desain yang dikompilasi kode D cukup cepat untuk membuatnya dapat digunakan sebagai bahasa scripting. Memanggang unit menguji langsung ke dalam bahasa sehingga Anda dapat menjalankan tes Anda hanya dengan memberikan bendera tambahan ke kompiler membantu dengan itu.

Namun, saya pikir perpustakaan pengujian unit hebat tidak lebih dari sekedar menemukan beberapa metode dan menjalankannya. Ambil QuickCheck Haskell sebagai contoh, yang memungkinkan Anda menguji hal-hal seperti "untuk semua x dan y, f (x, y) == f (y, x)". QuickCheck lebih baik dideskripsikan sebagai unit test generator dan memungkinkan Anda untuk menguji hal-hal pada tingkat yang lebih tinggi daripada "untuk input ini, saya mengharapkan output ini". QuickCheck dan Linq tidak jauh berbeda - keduanya merupakan bahasa khusus domain. Jadi, alih-alih mengandalkan dukungan pengujian unit ke bahasa, mengapa tidak menambahkan fitur yang diperlukan untuk membuat DSL praktis? Anda akan berakhir dengan tidak hanya pengujian unit, tetapi bahasa yang lebih baik sebagai hasilnya.

Doval
sumber
3
Untuk tetap berada di dunia .Net, ada FsCheck, yang merupakan port QuickCheck ke F #, dengan beberapa pembantu untuk digunakan dari C #.
Arthur van Leeuwen
Untuk tetap di dunia .NET? Pertanyaan ini tidak ada hubungannya dengan .NET.
Miles Rout
@MilesRout C # adalah bagian dari .NET. Pertanyaan dan jawaban sering berbicara tentang C #, dan pertanyaan itu bahkan berbicara tentang LINQ.
Zachary Dow
Pertanyaannya tidak ditandai .NET atau C #.
Miles Rout
@MilesRout Itu mungkin benar, tetapi Anda tidak bisa mengatakan bahwa itu tidak ada hubungannya dengan itu hanya karena tidak memiliki tag. :)
Zachary Dow
13

Karena pengujian, dan khususnya pengembangan yang digerakkan oleh pengujian, adalah fenomena yang sangat berlawanan dengan intuisi.

Hampir setiap programmer memulai karir mereka dengan percaya bahwa mereka jauh lebih baik dalam mengelola kompleksitas daripada yang sebenarnya. Fakta bahwa bahkan programmer terbesar tidak dapat menulis program besar dan kompleks tanpa kesalahan parah kecuali mereka menggunakan banyak tes regresi sangat mengecewakan dan bahkan memalukan bagi banyak praktisi. Oleh karena itu kecenderungan umum terhadap pengujian reguler bahkan di kalangan profesional yang seharusnya sudah tahu lebih baik.

Saya pikir fakta bahwa pengujian agama perlahan menjadi lebih utama dan diharapkan sebagian besar disebabkan oleh fakta bahwa dengan ledakan kapasitas penyimpanan dan daya komputasi, sistem yang lebih besar dari yang pernah dibangun - dan sistem yang sangat besar sangat rentan terhadap keruntuhan kompleksitas yang tidak dapat dikelola tanpa jaring pengaman dari uji regresi. Akibatnya, bahkan pengembang yang sangat keras kepala dan tertipu sekarang dengan enggan mengakui bahwa mereka perlu pengujian dan akan selalu perlu pengujian (jika ini terdengar seperti pengakuan pada pertemuan AA, ini cukup disengaja - membutuhkan jaring pengaman secara psikologis sulit untuk diterima bagi banyak orang. individu).

Sebagian besar bahasa populer saat ini berasal dari sebelum pergeseran sikap ini, sehingga mereka memiliki sedikit dukungan bawaan untuk tes: mereka memilikinya assert, tetapi tidak memiliki kontrak. Saya cukup yakin bahwa jika tren ini berlanjut, bahasa masa depan akan memiliki lebih banyak dukungan pada bahasa daripada tingkat perpustakaan.

Kilian Foth
sumber
3
Anda sedikit melebih-lebihkan kasus Anda. Sementara pengujian unit tidak diragukan lagi sangat penting, membangun program dengan cara yang tepat , cara yang meminimalkan kompleksitas yang tidak perlu, sama pentingnya, jika tidak lebih dari itu. Bahasa seperti Haskell memiliki sistem tipe yang meningkatkan keandalan dan kemampuan program yang ditulis di dalamnya, dan praktik terbaik dalam pengkodean dan desain menghindari banyak jebakan dari kode yang belum diuji, membuat pengujian unit menjadi kurang penting daripada yang seharusnya.
Robert Harvey
1
@RobertHarve ... dan pengujian unit adalah cara yang sangat baik untuk secara tidak langsung mendorong pengembang ke arah itu. Bekerja pada API sambil membuat tes, daripada saat menggunakannya dengan kode lain, membantu menempatkannya dalam pola pikir yang benar untuk membatasi atau menghilangkan abstraksi yang bocor atau panggilan metode ganjil. Saya tidak berpikir KillianFoth melebih-lebihkan apa pun.
Izkata
@Robert: Satu-satunya hal yang saya percaya dia melebih-lebihkan adalah "pengujian agama perlahan menjadi lebih utama" Jika perlahan-lahan didefinisikan dalam kerangka waktu geografis, dia mungkin tidak jauh ..... :)
mattnz
+1 Dalam pekerjaan saya saat ini, saya dikejutkan oleh perubahan pasang surut dalam sikap pengembangan dengan perpustakaan yang lebih baru dan teknologi yang tersedia. Untuk pertama kalinya dalam karir saya, orang-orang ini mengajari saya untuk menggunakan proses pengembangan yang lebih canggih, alih-alih saya merasa seperti berada di puncak bukit berteriak pada angin. Saya setuju itu hanya masalah waktu sebelum sikap ini menemukan ekspresi dalam sintaksis bahasa asli.
Rob
1
Maaf, satu pemikiran lagi: komentar Robert Harvey. Saat ini sistem tipe adalah pemeriksaan yang bagus, tetapi benar-benar gagal mendefinisikan batasan pada jenis - mereka mengatasi antarmuka, tetapi tidak membatasi perilaku yang benar. (yaitu 1 + 1 == 3 akan dikompilasi, tetapi mungkin atau mungkin tidak benar, tergantung pada implementasi +) Saya bertanya-tanya apakah tren berikutnya akan melihat sistem tipe yang lebih ekspresif yang menggabungkan apa yang kita anggap sebagai unit testing sekarang.
Rob
6

Banyak bahasa yang memiliki dukungan untuk pengujian. C menegaskan adalah tes bahwa program bisa gagal. Di situlah sebagian besar bahasa berhenti, tetapi Eiffel dan baru-baru ini Ada 2012 memiliki preinvarian (hal-hal yang harus dilewati oleh argumen untuk suatu fungsi) dan postinvarians (hal-hal yang harus dilewati oleh fungsi), dengan Ada menawarkan kemampuan untuk merujuk argumen awal di postinvariant. Ada 2012 juga menawarkan tipe invarian, jadi setiap kali sebuah metode dipanggil pada kelas Ada, tipe invarian diperiksa sebelum kembali.

Itu bukan jenis pengujian lengkap yang bisa diberikan kerangka pengujian yang baik kepada Anda, tetapi ini merupakan jenis pengujian penting yang dapat didukung oleh bahasa terbaik.

prosfila
sumber
2
Setelah melakukan sedikit pekerjaan di Eiffel dan menjadi pengguna pernyataan yang luas, pengalaman saya adalah bahwa apa pun yang dapat Anda lakukan yang bersifat kontrak membantu untuk menemukan banyak bug.
Blrfl
2

Beberapa pendukung bahasa fungsional yang diketik sangat berpendapat bahwa fitur bahasa ini mengurangi atau menghilangkan kebutuhan untuk tes unit.

Dua, imho, contoh bagus untuk ini adalah dari F # untuk Hiburan dan Keuntungan di sini dan di sini

Secara pribadi, saya masih percaya pada nilai unit test, tetapi ada beberapa poin yang valid. Misalnya, jika suatu keadaan ilegal tidak terwakili dalam kode, maka tidak hanya tidak perlu menulis unit test untuk kasus ini, itu tidak mungkin.

Pete
sumber
2

Saya berpendapat bahwa Anda telah melewatkan penambahan beberapa fitur yang diperlukan karena mereka tidak disorot untuk pengujian unit .

Misalnya, pengujian unit dalam C # terutama didorong dengan menggunakan atribut. Fitur Atribut Khusus menyediakan mekanisme ekstensi kaya yang memungkinkan kerangka kerja seperti NUnit untuk beralih dan bersaing, dengan hal-hal seperti pengujian berbasis Teori dan Parameter .

Ini membawa saya ke poin utama kedua saya - kita tidak cukup tahu tentang apa yang membuat testability yang baik untuk membuatnya menjadi bahasa. Laju inovasi dalam pengujian jauh lebih cepat daripada konstruksi bahasa lain sehingga kita perlu memiliki mekanisme yang fleksibel dalam bahasa kita untuk meninggalkan kebebasan untuk berinovasi.

Saya seorang pengguna tetapi tidak fanatik tentang TDD - ini sangat membantu dalam beberapa kasus terutama untuk meningkatkan pemikiran desain Anda. Ini tidak selalu berguna untuk sistem warisan yang lebih besar - pengujian tingkat lebih tinggi dengan data dan otomatisasi yang baik mungkin akan menghasilkan lebih banyak manfaat bersama dengan budaya inspeksi kode yang kuat .

Bacaan lain yang relevan:

Andy Dent
sumber