Apakah ada yang namanya memiliki terlalu banyak unit test?

139

Saya telah ditugaskan untuk menulis unit test untuk aplikasi yang ada. Setelah menyelesaikan file pertama saya, saya memiliki 717 baris kode uji untuk 419 baris kode asli.

Apakah rasio ini akan menjadi tidak terkelola saat kami meningkatkan cakupan kode kami?

Pemahaman saya tentang pengujian unit adalah untuk menguji setiap metode di kelas untuk memastikan bahwa setiap metode bekerja seperti yang diharapkan. Namun, dalam permintaan tarik, teknisi saya mencatat bahwa saya harus fokus pada pengujian tingkat yang lebih tinggi. Dia menyarankan pengujian 4-5 kasus penggunaan yang paling umum digunakan dengan kelas yang bersangkutan, daripada menguji setiap fungsi secara mendalam.

Saya percaya komentar pemimpin teknologi saya. Dia memiliki lebih banyak pengalaman daripada saya, dan dia memiliki naluri yang lebih baik dalam hal merancang perangkat lunak. Tetapi bagaimana tim multi-orang menulis tes untuk standar yang ambigu; yaitu, bagaimana saya tahu rekan-rekan saya dan saya berbagi ide yang sama untuk "kasus penggunaan paling umum"?

Bagi saya, cakupan 100% unit test adalah tujuan yang mulia, tetapi bahkan jika kita hanya mencapai 50%, kita akan tahu bahwa 100% dari 50% itu tercakup. Kalau tidak, menulis tes untuk bagian dari setiap file menyisakan banyak ruang untuk menipu.

pengguna2954463
sumber
145
Tergantung. Apakah Anda menulis permainan tic-tac-toe, atau Anda menulis kode untuk mengelola reaktor nuklir?
Bryan Oakley
11
Dengan cukup banyak unit test, Anda dapat mendeteksi masalah implementasi perangkat keras yang eksotis seperti bug Pentium FDIV atau korelasi dalam primitif kriptografi, sehingga sepertinya tidak ada batasan masa lalu yang tidak ada lagi pengujian unit lebih lanjut yang berguna. Hanya batas praktis kapan terlalu mahal.
Nat
5
Pengujian di level yang lebih tinggi akan memberi Anda perspektif yang lebih baik tentang cakupan yang sebenarnya. Dengan cakupan nyata yang saya maksudkan adalah yang lebih mungkin terjadi selama penggunaan reguler sistem. Itulah jenis liputan yang ingin Anda capai terlebih dahulu. Dalam 50% yang terakhir untuk mencapai bisa memiliki YAGNI atau kode mati yang pernah dihapus akan berkontribusi untuk meningkatkan cakupan keseluruhan juga.
Laiv
5
Jika Anda mendapatkan terlalu banyak tes (yang tampaknya tidak Anda miliki saat ini) masalah yang paling mungkin adalah bahwa kode yang Anda uji terlalu banyak. Jadi tanggung jawab tunggal tidak dipatuhi. Ketika kode terpecah dengan baik, pengujian juga tidak akan membuat banyak beban. Jika kelas melakukan banyak hal, memiliki banyak efek samping dll. Itu akan menjadi mimpi buruk.
Luc Franken
12
Dokumen pengujian sqlite menyenangkan dibaca: sqlite.org/testing.html . Kutipan: "perpustakaan SQLite terdiri dari sekitar 122,9 KSLOC dari kode C. Dengan perbandingan, proyek ini memiliki 745 kali lebih banyak kode uji dan skrip pengujian - 91596.1 KSLOC."
user60561

Jawaban:

180

Ya, dengan cakupan 100% Anda akan menulis beberapa tes yang tidak Anda butuhkan. Sayangnya, satu-satunya cara yang dapat diandalkan untuk menentukan tes mana yang tidak Anda butuhkan adalah menulis semuanya, lalu tunggu 10 tahun atau lebih untuk melihat tes mana yang tidak pernah gagal.

Mempertahankan banyak tes biasanya tidak bermasalah. Banyak tim memiliki integrasi otomatis dan pengujian sistem di atas 100% cakupan pengujian unit.

Namun, Anda tidak berada dalam fase uji pemeliharaan, Anda sedang mengejar ketinggalan. Adalah jauh lebih baik untuk memiliki 100% kelas Anda pada cakupan tes 50% daripada 50% kelas Anda pada cakupan tes 100%, dan pemimpin Anda tampaknya berusaha membuat Anda mengalokasikan waktu Anda dengan tepat. Setelah Anda memiliki garis dasar itu, maka langkah selanjutnya biasanya mendorong 100% dalam file yang diubah maju.

Karl Bielefeldt
sumber
11
Terima kasih atas jawaban anda. Itu membantu menempatkan pertanyaan saya dalam perspektif dan mengatasi masalah sebenarnya - sikap saya! +1
user2954463
43
@astra Sikap Anda tidak terlalu buruk. Ada baiknya mempertanyakan mengapa. Untuk menjawab pertanyaan Anda yang lain, pertanyaan yang sangat bagus: "Bagaimana saya tahu teman-teman saya dan saya berbagi ide yang sama untuk" kasus penggunaan paling umum "? Anda meminta mereka untuk melihat tes Anda. Lihat mereka. Bicara tentang mereka. Anda akan belajar banyak dan mungkin mereka juga akan melakukannya. Tes peninjauan kode jarang membuang-buang waktu. Meskipun saya cenderung melakukan tambang di terminal daripada ruang konferensi
candied_orange
18
Sebuah tes yang tidak pernah gagal dalam 10 tahun bahkan tidak menjamin itu tidak perlu, itu bisa berakhir gagal di tahun 11.
Pharap
24
Secara pragmatis, Anda bisa mengambil pendekatan sebaliknya. Tulis tes yang menurut Anda mencakup kasus-kasus umum. Tetapi kemudian, setiap kali Anda menemui kegagalan, tulislah ujian untuk membahas bidang itu.
stannius
10
@Pharap Satu-satunya masalah saya dengan jawaban ini adalah bahwa ada asumsi implisit bahwa tes hanya dapat menambah nilai ketika gagal. Unit test yang baik juga menyediakan dokumentasi hidup yang bagus. Ini juga menambah nilai ketika Anda menulis tes, dengan memaksa Anda untuk berpikir tentang reusability / composability / encapulation. Kode yang belum diuji dalam pengalaman saya cenderung menjadi binatang monolitik yang tidak fleksibel.
ArTs
66

Jika Anda telah bekerja pada basis kode besar yang dibuat menggunakan Test Driven Development, Anda akan tahu bahwa mungkin ada terlalu banyak tes unit. Dalam beberapa kasus, sebagian besar upaya pengembangan terdiri dari memperbarui tes berkualitas rendah yang akan lebih baik diimplementasikan sebagai invarian, prekondisi, dan pemeriksaan pascakondisi di kelas yang relevan, pada saat run-time (yaitu pengujian sebagai efek samping dari tes tingkat yang lebih tinggi ).

Masalah lain adalah penciptaan desain yang berkualitas rendah, menggunakan teknik desain yang didorong oleh pemujaan kargo, yang menghasilkan banyak hal untuk diuji (lebih banyak kelas, antarmuka, dll). Dalam hal ini, beban mungkin tampak memperbarui kode pengujian, tetapi masalah sebenarnya adalah desain yang berkualitas buruk.

Frank Hileman
sumber
16
Terpilih untuk menunjukkan pra-kondisi, pasca-kondisi dan invarian harus diperlakukan sebagai unit-testing. Dengan begitu setiap penggunaan adalah unit-test ketika kode debug itu aktif.
Persixty
Ini adalah jawaban yang bagus dan selaras dengan pengalaman saya.
Tony Ennis
Dan satu masalah lagi: Jika Anda memiliki checkin yang terjaga keamanannya (Anda benar-benar harus!) Memiliki kualitas rendah dalam jumlah besar, bahkan mungkin tes yang berjalan lama akan memperlambat semuanya tanpa memberikan manfaat nyata. Dan jelas fakta yang menyenangkan di mana Anda mengubah satu hal di kelas dan ratusan tes gagal.
Voo
3
Ini adalah jawaban yang jauh lebih baik daripada yang diterima! "Dalam beberapa kasus, sebagian besar upaya pengembangan terdiri dari memperbarui tes berkualitas rendah" - Saya pernah mengalami ini dan itu menyebalkan. Lebih dari tidak memiliki tes sama sekali, dalam beberapa hal.
Benjamin Hodgson
36

Jawaban untuk pertanyaan Anda

Apakah ada yang namanya memiliki terlalu banyak unit test?

Tentu ... Anda bisa, misalnya, memiliki beberapa tes yang tampaknya berbeda pada pandangan pertama tetapi benar-benar menguji hal yang sama (secara logis tergantung pada baris yang sama dari kode aplikasi "menarik" yang sedang diuji).

Atau Anda dapat menguji internal kode Anda yang tidak pernah muncul ke luar (yaitu, bukan bagian dari kontrak antarmuka apa pun), di mana orang dapat berdebat tentang apakah itu masuk akal, sama sekali. Misalnya kata-kata yang tepat dari pesan log internal atau apa pun.

Saya telah ditugaskan untuk menulis unit test untuk aplikasi yang ada. Setelah menyelesaikan file pertama saya, saya memiliki 717 baris kode uji untuk 419 baris kode asli.

Itu menurut saya cukup normal. Tes Anda menghabiskan banyak baris kode pada pengaturan dan teardown di atas tes yang sebenarnya. Rasio dapat meningkat, atau mungkin tidak. Saya sendiri cukup uji berat, dan sering menginvestasikan lebih banyak waktu dan lokasi pada tes daripada kode yang sebenarnya.

Apakah rasio ini akan menjadi tidak terkelola saat kami meningkatkan cakupan kode kami?

Rasio tidak menjadi faktor dalam begitu banyak. Ada kualitas tes lain yang cenderung membuatnya tidak terkendali. Jika Anda secara teratur harus memperbaiki sejumlah tes ketika melakukan perubahan yang agak sederhana dalam kode Anda, Anda harus memperhatikan alasannya. Dan itu bukan berapa banyak baris yang Anda miliki, tetapi bagaimana Anda mendekati pengkodean tes.

Pemahaman saya tentang pengujian unit adalah untuk menguji setiap metode di kelas untuk memastikan bahwa setiap metode bekerja seperti yang diharapkan.

Itu benar untuk tes "unit" dalam arti yang ketat. Di sini, "unit" menjadi sesuatu seperti metode atau kelas. Maksud dari pengujian "unit" adalah hanya menguji satu unit kode tertentu, bukan keseluruhan sistem. Idealnya Anda akan menghapus seluruh sisa sistem (menggunakan ganda atau yang lainnya).

Namun, dalam permintaan tarik, teknisi saya mencatat bahwa saya harus fokus pada pengujian tingkat yang lebih tinggi.

Lalu Anda jatuh ke dalam perangkap dengan asumsi orang benar-benar berarti tes unit ketika mereka mengatakan tes unit. Saya telah bertemu banyak programmer yang mengatakan "unit test" tetapi berarti sesuatu yang sangat berbeda.

Dia menyarankan pengujian 4-5 kasus penggunaan yang paling umum digunakan dengan kelas yang bersangkutan, daripada menguji setiap fungsi secara mendalam.

Tentu, hanya berkonsentrasi pada 80% teratas dari kode penting mengurangi beban juga ... Saya menghargai bahwa Anda sangat memikirkan bos Anda, tetapi ini tidak menurut saya sebagai pilihan optimal.

Bagi saya, cakupan 100% unit test adalah tujuan yang mulia, tetapi bahkan jika kita hanya mencapai 50%, kita akan tahu bahwa 100% dari 50% itu tercakup.

Saya tidak tahu apa "cakupan uji unit". Saya berasumsi maksud Anda "cakupan kode", yaitu bahwa setelah menjalankan rangkaian uji, setiap baris kode (= 100%) telah dieksekusi setidaknya satu kali.

Ini adalah metrik rata-rata yang bagus, tetapi sejauh ini bukan standar terbaik yang bisa digunakan. Hanya mengeksekusi baris kode bukanlah keseluruhan gambar; misalnya, ini tidak menjelaskan jalur yang berbeda melalui cabang yang rumit dan bersarang. Ini lebih merupakan metrik yang mengarahkan jarinya ke potongan kode yang diuji terlalu sedikit (jelas, jika kelas dengan cakupan kode 10% atau 5%, maka ada sesuatu yang salah); di sisi lain, cakupan 100% tidak akan memberi tahu Anda apakah Anda telah cukup menguji atau apakah Anda telah menguji dengan benar.

Tes integrasi

Ini mengganggu saya secara substansial ketika orang-orang terus-menerus berbicara tentang pengujian unit hari ini, secara default. Menurut pendapat saya (dan pengalaman), pengujian unit sangat bagus untuk perpustakaan / API; di area yang lebih berorientasi bisnis (di mana kita berbicara tentang kasus penggunaan seperti pada pertanyaan yang ada), mereka tidak selalu merupakan pilihan terbaik.

Untuk kode aplikasi umum dan dalam bisnis rata-rata (di mana menghasilkan uang, mencapai tenggat waktu, dan memenuhi kepuasan pelanggan adalah penting, dan Anda terutama ingin menghindari bug yang berada langsung di wajah pengguna, atau yang dapat menyebabkan bencana nyata - kami tidak bicara peluncuran roket NASA di sini), tes integrasi atau fitur jauh lebih berguna.

Mereka berjalan seiring dengan Pengembangan Berbasis Perilaku atau Pengembangan Berbasis Fitur; mereka tidak bekerja dengan unit test (ketat), menurut definisi.

Agar singkat (ish), tes integrasi / fitur melatih seluruh tumpukan aplikasi. Dalam aplikasi berbasis web, ini akan bertindak seperti browser yang mengklik aplikasi (dan tidak, jelas itu tidak harus sesederhana itu, ada kerangka kerja yang sangat kuat di luar sana untuk melakukan itu - lihat http: // mentimun. io misalnya).

Oh, untuk menjawab pertanyaan terakhir Anda: Anda membuat seluruh tim Anda memiliki cakupan tes yang tinggi dengan memastikan bahwa fitur baru hanya diprogram setelah uji fitur telah diterapkan dan gagal. Dan ya, itu berarti setiap fitur. Ini menjamin Anda cakupan fitur 100% (positif). Ini secara definisi menjamin bahwa fitur aplikasi Anda tidak akan "hilang". Itu tidak menjamin cakupan kode 100% (misalnya, kecuali jika Anda secara aktif memprogram fitur negatif, Anda tidak akan melakukan penanganan kesalahan / penanganan pengecualian).

Itu tidak menjamin Anda aplikasi bebas bug; tentu saja Anda akan ingin menulis tes fitur untuk situasi buggy yang jelas atau sangat berbahaya, input pengguna yang salah, peretasan (misalnya, manajemen sesi sekitar, keamanan dan semacamnya) dll .; tetapi bahkan hanya memprogram tes positif memiliki manfaat luar biasa dan cukup layak dengan kerangka kerja modern yang kuat.

Tes fitur / integrasi jelas memiliki cacing mereka sendiri (misalnya, kinerja; pengujian berlebihan terhadap kerangka kerja pihak ketiga; karena Anda biasanya tidak menggunakan ganda, mereka juga cenderung lebih sulit untuk menulis, dalam pengalaman saya ...), tetapi saya d mengambil aplikasi 100% positif yang diuji fitur lebih dari 100% kode-cakupan-aplikasi yang diuji (bukan perpustakaan!) setiap hari.

AnoE
sumber
1
Tes integrasi sangat bagus tetapi tidak ada penggantian untuk pengujian unit, juga tidak untuk aplikasi bisnis. Ada beberapa masalah dengan mereka: a) mereka menurut definisi membutuhkan waktu lama untuk berjalan (itu juga berarti tes tambahan cukup banyak tidak berguna), b) mereka membuatnya sangat sulit untuk menentukan masalah yang sebenarnya (oh 50 tes integrasi gagal, perubahan apa yang menyebabkan hal itu?) dan c) mereka menutupi jalur kode yang sama berulang kali.
Voo
1
a) merupakan masalah karena itu membuat menjalankan tes pada check-in yang terjaga keamanannya dan membuatnya kurang mungkin bahwa programmer akan menjalankan tes berulang kali saat berkembang, yang digabungkan dengan b) mengurangi efisiensi dan kemampuan untuk dengan cepat mendiagnosis bug. c) berarti bahwa mengubah satu hal kecil dapat dengan mudah menyebabkan puluhan atau ratusan tes integrasi Anda gagal, yang berarti Anda akan menghabiskan banyak waktu untuk memperbaikinya. Ini juga berarti bahwa tes integrasi sebagian besar hanya menguji jalur bahagia, karena menulis tes ini ditargetkan rumit atau tidak mungkin.
Voo
1
@Vo, semua yang Anda tulis adalah benar, dan sejauh yang saya tahu saya sudah menyebutkan semua masalah yang Anda catat dalam jawaban ...
AnoE
Jika Anda setuju dengan ringkasan itu, saya benar-benar tidak melihat bagaimana Anda bisa sampai pada kesimpulan bahwa Anda lebih suka tes integrasi daripada tes unit. Suite tes integrasi komprehensif untuk program besar membutuhkan waktu berjam-jam atau bahkan berhari-hari untuk dijalankan, sangat bagus untuk dimiliki tetapi hampir tidak berguna selama pengembangan aktual. Dan tes penerimaan Anda (yang dilakukan semua orang, bukan?) Akan menangkap banyak masalah yang sama yang akan ditemukan oleh tes integrasi yang akan terlewatkan oleh tes unit - sebaliknya tidak benar.
Voo
24

Ya, mungkin untuk memiliki terlalu banyak unit test. Jika Anda memiliki cakupan 100% dengan tes unit dan tidak ada tes integrasi misalnya, Anda memiliki masalah yang jelas.

Beberapa skenario:

  1. Anda merekayasa secara berlebihan tes Anda ke implementasi tertentu. Maka Anda harus membuang unit test ketika Anda refactor, belum lagi ketika Anda mengubah implementasi (titik nyeri yang sangat sering ketika melakukan optimasi kinerja).

    Keseimbangan yang baik antara tes unit dan tes integrasi mengurangi masalah ini tanpa kehilangan cakupan yang signifikan.

  2. Anda dapat memiliki cakupan yang masuk akal untuk setiap komit dengan 20% dari tes yang Anda miliki, meninggalkan 80% sisanya untuk integrasi atau setidaknya lulus tes yang terpisah; efek negatif utama yang Anda lihat dalam skenario ini adalah perubahan lambat karena Anda harus menunggu waktu yang lama untuk melakukan tes.

  3. Anda memodifikasi terlalu banyak kode untuk memungkinkan Anda mengujinya; misalnya, saya telah melihat banyak penyalahgunaan IoC pada komponen yang tidak akan perlu dimodifikasi atau setidaknya itu mahal dan prioritas rendah untuk menggeneralisasi mereka, tetapi orang menginvestasikan banyak waktu menggeneralisasi dan refactoring mereka untuk memungkinkan unit mengujinya .

Saya terutama setuju dengan saran untuk mendapatkan cakupan 50% pada 100% file, bukannya cakupan 100% pada 50% file; fokuskan upaya awal Anda pada kasus positif yang paling umum, dan kasus negatif yang paling berbahaya, jangan berinvestasi terlalu banyak pada penanganan kesalahan dan jalur yang tidak biasa, bukan karena mereka tidak penting tetapi karena Anda memiliki waktu terbatas dan alam semesta pengujian tanpa batas, jadi Anda perlu memprioritaskan pada kasus apa pun.

Bruno Guardia
sumber
2
Yang tidak menjadi masalah dengan tes unit, tetapi dengan organisasi karena memiliki prioritas salah dengan menuntut nomor tertentu untuk cakupan tes unit tanpa menghabiskan sumber daya untuk membuat dan melaksanakan tes yang tepat di tingkat lain.
jwenting
2
Setuju kuat pada # 3 dan juga akan memperpanjang untuk secara manual meneruskan contoh kelas tingkat rendah ke kelas tingkat lebih tinggi. Jika hal tingkat tinggi bergantung pada hal tingkat rendah untuk menyelesaikan sesuatu, itu tidak masalah. Jika menyembunyikan detail itu dari penelepon, saya akan menyebut desain yang bagus. Tetapi jika Anda kemudian membuat bagian level rendah dari antarmuka level tinggi dan membuat penelepon lulus karena membuat tes Anda cantik, sekarang ekornya mengibas-ngibaskan anjing. (Jika benda tingkat rendah digunakan kembali di banyak tempat, dan banyak berubah, itu akan mengubah banyak hal. Dalam pengalaman saya yang tidak biasa.)
johncip
Saya suka uraian Anda @johncip, pasti itu adalah contoh yang sering tentang bagaimana kelas yang bagus menjadi mengerikan dengan menambahkan sekelompok parameter yang tidak perlu yang diperlukan untuk konstruktor ...
Bruno Guardia
19

Perlu diingat bahwa setiap tes memiliki biaya serta manfaat. Kerugian meliputi:

  • ujian harus ditulis;
  • tes membutuhkan (biasanya jumlah yang sangat kecil) untuk dijalankan;
  • sebuah tes harus dipertahankan dengan kode - tes harus berubah ketika API mereka menguji perubahan;
  • Anda mungkin harus mengubah desain Anda untuk menulis tes (meskipun perubahan ini biasanya menjadi lebih baik).

Jika biayanya melebihi manfaatnya, tes lebih baik tidak ditulis. Misalnya, jika fungsionalitas sulit untuk diuji, API sering berubah, kebenarannya relatif tidak penting, dan kemungkinan tes menemukan cacat rendah, Anda mungkin lebih baik tidak menulisnya.

Adapun rasio tes untuk kode tertentu, jika kode tersebut cukup logis, maka rasio tersebut dapat dijamin. Namun, mungkin tidak layak mempertahankan rasio tinggi di seluruh aplikasi yang khas.

Rahasia Solomonoff
sumber
12

Ya, ada yang namanya terlalu banyak unit test.

Sementara pengujian baik setiap unit tes adalah:

  • Potensi beban pemeliharaan yang tergabung erat dengan API

  • Waktu yang bisa dihabiskan untuk hal lain

  • Sepotong waktu dalam suite Tes Unit
  • Mungkin menambahkan tidak ada nilai nyata karena ini merupakan duplikat dari beberapa tes lain yang memiliki peluang sangat kecil yang beberapa tes lain akan lulus dan tes ini akan gagal.

Adalah bijaksana untuk membidik cakupan kode 100% tetapi jauh dari itu berarti serangkaian tes yang masing-masing secara independen menyediakan cakupan kode 100% pada beberapa titik entri yang ditentukan (fungsi / metode / panggilan dll.).

Meskipun mengingat betapa sulitnya untuk mencapai cakupan yang baik dan mengusir bug, kebenarannya mungkin adalah bahwa ada yang namanya 'unit test yang salah' sebanyak 'terlalu banyak unit test'.

Pragmatik untuk sebagian besar kode menunjukkan:

  1. Pastikan Anda memiliki cakupan 100% dari titik masuk (semuanya diuji entah bagaimana) dan bertujuan untuk mendekati cakupan kode 100% dari jalur 'non-kesalahan'.

  2. Uji nilai atau ukuran min / maks yang relevan

  3. Uji apa pun yang Anda anggap sebagai kasus khusus yang lucu, terutama nilai-nilai 'aneh'.

  4. Ketika Anda menemukan bug, tambahkan unit test yang akan mengungkapkan bug itu dan pikirkan apakah ada kasus serupa yang harus ditambahkan.

Untuk algoritma yang lebih kompleks, pertimbangkan juga:

  1. Melakukan beberapa pengujian massal terhadap lebih banyak kasus.
  2. Membandingkan hasil dengan implementasi 'brute-force' dan memeriksa invarian.
  3. Menggunakan beberapa metode untuk menghasilkan kasus uji acak dan memeriksa terhadap kekuatan kasar dan kondisi pasca termasuk invarian.

Misalnya memeriksa algoritma pengurutan dengan beberapa input acak dan memvalidasi data diurutkan pada akhirnya dengan memindai itu.

Saya akan mengatakan memimpin teknologi Anda mengusulkan pengujian 'pantat telanjang minimal'. Saya menawarkan 'pengujian kualitas nilai tertinggi' dan ada spektrum di antaranya.

Mungkin senior Anda tahu komponen yang Anda bangun akan tertanam di bagian yang lebih besar dan unit diuji lebih menyeluruh ketika terintegrasi.

Pelajaran utama adalah menambahkan tes ketika bug ditemukan. Yang membawa saya pelajaran terbaik saya tentang mengembangkan unit test:

Fokus pada unit bukan sub-unit. Jika Anda membangun unit dari sub-unit, tulislah tes yang sangat mendasar untuk sub-unit sampai mereka masuk akal dan capai cakupan yang lebih baik dengan menguji sub-unit melalui unit-unit pengendali mereka.

Jadi jika Anda sedang menulis kompiler dan perlu menulis tabel simbol (katakanlah). Dapatkan tabel simbol dan jalankan dengan tes dasar dan kemudian bekerja pada (katakanlah) pengurai deklarasi yang mengisi tabel. Hanya tambahkan tes lebih lanjut ke unit simbol 'berdiri sendiri' jika Anda menemukan bug di dalamnya. Kalau tidak, tingkatkan cakupan dengan unit test pada parser deklarasi dan kemudian seluruh kompiler.

Yang mendapat untung besar (satu tes keseluruhan menguji beberapa komponen) dan meninggalkan lebih banyak kapasitas untuk desain ulang dan perbaikan karena hanya antarmuka 'luar' yang digunakan dalam tes yang cenderung lebih stabil.

Ditambah dengan pra-kondisi pengujian kode debug, kondisi pasca termasuk invarian di semua tingkatan Anda mendapatkan cakupan pengujian maksimum dari implementasi tes minimal.

Persixty
sumber
4
Saya tidak akan mengatakan bahwa cakupan 100% bersifat pragmatis. Cakupan 100% adalah standar yang sangat tinggi.
Bryan Oakley
Sayangnya bahkan metode acak dapat melewatkan kesalahan. Tidak ada pengganti untuk bukti, bahkan jika informal.
Frank Hileman
@BryanOakley Point diambil. Itu berlebihan. Tetapi lebih penting untuk mendekatinya daripada orang yang memberi kredit. "Aku menguji jalan yang mudah itu semua baik" selalu akan menimbulkan masalah nanti
Persixty
@ Frankhileman Pertanyaannya bukan "Apakah pengujian unit pengganti yang baik untuk merancang perangkat lunak dengan hati-hati, logika pemeriksaan statis dan algoritma pembuktian" maka jawabannya adalah 'tidak'. Tidak ada metode yang akan menghasilkan perangkat lunak berkualitas tinggi sendiri.
Persixty
3

Pertama, itu tidak selalu masalah untuk memiliki lebih banyak jalur pengujian daripada kode produksi. Kode uji adalah (atau seharusnya) linier dan mudah dipahami - kompleksitasnya sangat, sangat rendah, terlepas dari apakah kode produksinya. Jika kompleksitas pengujian mulai mendekati kode produksi, maka kemungkinan Anda memang memiliki masalah.

Ya, adalah mungkin untuk memiliki terlalu banyak unit test - eksperimen pemikiran sederhana menunjukkan bahwa Anda dapat melanjutkan menambahkan tes yang tidak memberikan nilai tambahan, dan bahwa semua tes tambahan itu dapat menghambat setidaknya beberapa refactoring.

Saran untuk menguji hanya kasus yang paling umum adalah cacat, menurut pendapat saya. Ini mungkin bertindak sebagai tes asap untuk menghemat waktu uji sistem, tetapi tes yang sangat berharga menangkap kasus yang sulit dilakukan di seluruh sistem. Sebagai contoh, injeksi kesalahan gagal alokasi memori yang terkontrol dapat digunakan untuk menjalankan jalur pemulihan yang mungkin kualitasnya benar-benar tidak diketahui. Atau berikan nol sebagai nilai yang Anda tahu akan digunakan sebagai pembagi (atau angka negatif yang akan di-root), dan pastikan Anda tidak mendapatkan pengecualian yang tidak tertangani.

Tes paling berharga berikutnya adalah tes yang menggunakan batas ekstrim atau titik batas. Misalnya, fungsi yang menerima bulan (berbasis 1) tahun harus diuji dengan 0, 1, 12 dan 13, sehingga Anda tahu bahwa transisi yang valid-tidak valid ada di tempat yang tepat. Pengujian berlebih juga menggunakan 2.11 untuk pengujian ini.

Anda berada dalam posisi yang sulit, karena Anda harus menulis tes untuk kode yang ada. Lebih mudah untuk mengidentifikasi kasus tepi saat Anda menulis (atau akan menulis) kode.

Toby Speight
sumber
3

Pemahaman saya tentang pengujian unit adalah untuk menguji setiap metode di kelas untuk memastikan bahwa setiap metode bekerja seperti yang diharapkan.

Pemahaman ini salah.

Unit test memverifikasi perilaku dari unit yang diuji .

Dalam pengertian itu suatu unit tidak harus "metode dalam kelas". Saya suka definisi unit oleh Roy Osherove dalam The Art of Unit Testing :

Unit adalah semua kode produksi yang memiliki alasan yang sama untuk berubah.

Berdasarkan hal ini, tes unit harus memverifikasi setiap perilaku kode yang diinginkan . Dimana "keinginan" kurang lebih diambil dari persyaratan.


Namun, dalam permintaan tarik, teknisi saya mencatat bahwa saya harus fokus pada pengujian tingkat yang lebih tinggi.

Dia benar, tetapi dengan cara yang berbeda dari yang dia pikirkan.

Dari pertanyaan Anda, saya mengerti bahwa Anda adalah "penguji khusus" dalam proyek itu.

Kesalahpahaman besar adalah bahwa ia mengharapkan Anda untuk menulis tes unit (berbeda dengan "tes menggunakan kerangka pengujian unit"). Menulis tes ynit adalah tanggung jawab pengembang , bukan penguji (di dunia yang ideal, saya tahu ...). Di sisi lain Anda menandai pertanyaan ini dengan TDD, yang menyiratkan hal ini.

Tugas Anda sebagai tester adalah menulis (atau menjalankan secara manual) modul dan / atau tes aplikasi. Dan tes semacam ini terutama harus memverifikasi bahwa semua unit bekerja bersama dengan lancar. Itu berarti Anda harus memilih test case Anda sehingga setiap unit dieksekusi setidaknya sekali . Dan cek itu dijalankan. Hasil yang sebenarnya kurang penting karena dapat berubah dengan persyaratan di masa depan.

Untuk menekankan analogi dump mobil sekali lagi: Berapa banyak tes yang dilakukan dengan mobil di ujung jalur perakitan? Tepat satu: ia harus pergi ke tempat parkir sendiri ...

Intinya di sini adalah:

Kita perlu menyadari perbedaan antara "tes unit" dan "tes otomatis menggunakan kerangka pengujian unit".


Bagi saya, cakupan 100% unit test adalah tujuan yang mulia, tetapi bahkan jika kita hanya mencapai 50%, kita akan tahu bahwa 100% dari 50% itu tercakup.

Tes unit adalah jaring pengaman. Mereka memberi Anda kepercayaan diri untuk memperbaiki kode Anda untuk mengurangi utang teknis atau menambah perilaku baru tanpa takut merusak perilaku yang sudah diterapkan.

Anda tidak perlu cakupan kode 100%.

Tetapi Anda membutuhkan cakupan perilaku 100%. (Ya, cakupan kode dan cakupan perilaku berkorelasi entah bagaimana, tetapi mereka tidak identik karenanya.)

Jika Anda memiliki cakupan perilaku kurang dari 100%, rangkaian test suite Anda yang berhasil tidak berarti apa-apa karena Anda dapat mengubah beberapa perilaku yang belum diuji. Dan Anda akan diperhatikan oleh klien Anda sehari setelah rilis Anda online ...


Kesimpulan

Beberapa tes lebih baik daripada tidak ada tes. Tanpa keraguan!

Tetapi tidak ada yang namanya memiliki terlalu banyak unit test.

Ini karena setiap pengujian unit memverifikasi harapan tunggal tentang perilaku kode . Dan Anda tidak dapat menulis lebih banyak unit test daripada yang Anda harapkan pada kode Anda. Dan lubang dalam safety harness Anda adalah peluang untuk perubahan yang tidak diinginkan untuk merusak sistem produksi.

Timothy Truckle
sumber
2

Pastinya ya. Saya pernah menjadi SDET untuk perusahaan perangkat lunak besar. Tim kecil kami harus menjaga kode uji yang dulu ditangani oleh tim yang jauh lebih besar. Selain itu, produk kami memiliki beberapa dependensi yang terus-menerus memperkenalkan perubahan yang melanggar, yang berarti pemeliharaan pengujian konstan bagi kami. Kami tidak memiliki opsi untuk meningkatkan ukuran tim, jadi kami harus membuang ribuan tes yang kurang berharga ketika gagal. Kalau tidak, kita tidak akan pernah bisa mengikuti cacat.

Sebelum Anda menganggap ini sebagai masalah manajemen semata, pertimbangkan bahwa banyak proyek di dunia nyata mengalami pengurangan staf saat mereka mendekati status warisan. Kadang-kadang bahkan mulai terjadi tepat setelah rilis pertama.

mrog
sumber
4
"Selain itu, produk kami memiliki beberapa dependensi yang secara konstan memperkenalkan perubahan yang melanggar, yang berarti pemeliharaan pengujian konstan bagi kami." - Tes yang Anda katakan membutuhkan suara pemeliharaan seperti yang berharga jika dependensi Anda terus-menerus rusak.
CodeMonkey
2
Itu bukan masalah dengan tes, tetapi dengan organisasi.
jwenting
2
@CodeMonkey Ketergantungan tidak rusak. Mereka diperbarui dengan cara yang membutuhkan perubahan pada produk kami. Ya, tes itu sangat berharga, tetapi tidak sama berharganya dengan yang lain. Tes otomatis paling berharga ketika tes manual setara sulit.
mrog
2
@jwenting Ya, ini masalah organisasi, bukan masalah kode. Tapi itu tidak mengubah fakta bahwa ada terlalu banyak tes. Tes gagal yang tidak dapat diselidiki tidak berguna, terlepas dari penyebabnya.
mrog
Apa itu "SDET"?
Peter Mortensen
1

Memiliki lebih banyak baris kode pengujian daripada kode produk tidak selalu menjadi masalah, dengan asumsi Anda sedang melakukan refactoring kode pengujian Anda untuk menghilangkan copy-paste.

Apa masalah adalah memiliki tes yang merupakan cermin dari implementasi Anda, tanpa makna bisnis - misalnya, tes penuh dengan ejekan dan bertopik dan hanya menyatakan bahwa suatu metode memanggil beberapa metode lain.

Kutipan yang bagus dalam kertas "mengapa sebagian besar pengujian unit adalah pemborosan" adalah bahwa pengujian unit harus memiliki "oracle of correctness yang luas, formal, independen, dan ... nilai bisnis yang dapat dilukiskan"

Wrschneider
sumber
0

Satu hal yang saya tidak lihat disebutkan adalah bahwa tes Anda harus cepat dan mudah bagi pengembang untuk dijalankan kapan saja.

Anda tidak ingin harus masuk ke kontrol sumber dan menunggu satu jam atau lebih (tergantung pada ukuran basis kode Anda) sebelum tes selesai untuk melihat apakah perubahan Anda merusak sesuatu - Anda ingin dapat melakukannya pada mesin Anda sendiri sebelum Anda masuk ke kontrol sumber (atau setidaknya, sebelum Anda mendorong perubahan Anda). Idealnya, Anda harus dapat menjalankan tes dengan satu skrip atau tombol.

Dan ketika Anda menjalankan tes-tes tersebut secara lokal, Anda ingin mereka berjalan cepat - dalam urutan detik. Lebih lambat, dan Anda akan tergoda untuk tidak menjalankannya cukup atau tidak sama sekali.

Jadi, memiliki begitu banyak tes yang menjalankan semuanya membutuhkan waktu beberapa menit, atau memiliki beberapa tes yang terlalu rumit, bisa menjadi masalah.

mmathis
sumber