(Mengapa) apakah penting bahwa unit test tidak menguji dependensi?

103

Saya memahami nilai pengujian otomatis dan menggunakannya di mana pun masalahnya cukup ditentukan sehingga saya bisa menghasilkan kasus pengujian yang baik. Namun, saya perhatikan bahwa beberapa orang di sini dan di StackOverflow menekankan pengujian hanya pada satu unit, bukan ketergantungannya. Di sini saya gagal melihat manfaatnya.

Mengolok-olok / mematikan untuk menghindari ketergantungan pengujian menambah kerumitan pada tes. Ini menambahkan persyaratan fleksibilitas / decoupling buatan ke kode produksi Anda untuk mendukung mengejek. (Saya tidak setuju dengan siapa pun yang mengatakan ini mempromosikan desain yang baik. Menulis kode tambahan, memperkenalkan hal-hal seperti kerangka kerja injeksi ketergantungan, atau menambahkan kompleksitas pada basis kode Anda untuk membuat hal-hal lebih fleksibel / pluggable / extensible / dipisahkan dengan tanpa menggunakan kasus nyata adalah overengineering, tidak desain yang bagus.)

Kedua, menguji dependensi berarti bahwa kode tingkat rendah kritis yang digunakan di mana-mana diuji dengan input selain dari orang yang menulis tes itu secara eksplisit memikirkannya. Saya telah menemukan banyak bug dalam fungsionalitas tingkat rendah dengan menjalankan tes unit pada fungsionalitas tingkat tinggi tanpa mengejek fungsionalitas tingkat rendah yang menjadi sandarannya. Idealnya ini ditemukan oleh unit test untuk fungsionalitas tingkat rendah, tetapi kasus yang terlewat selalu terjadi.

Apa sisi lain dari ini? Apakah benar-benar penting bahwa unit test tidak juga menguji dependensinya? Jika demikian, mengapa?

Sunting: Saya dapat memahami nilai mengejek dependensi eksternal seperti database, jaringan, layanan web, dll. (Terima kasih kepada Anna Lear karena memotivasi saya untuk mengklarifikasi ini.) Saya merujuk pada dependensi internal , yaitu kelas lain, fungsi statis, dll. yang tidak memiliki dependensi eksternal langsung.

dsimcha
sumber
14
"overengineering, desain yang tidak bagus". Anda harus memberikan lebih banyak bukti dari itu. Banyak orang tidak akan menyebutnya "lebih dari rekayasa", tetapi "praktik terbaik".
S.Lott
9
@ S.Lott: Tentu saja ini subjektif. Saya hanya tidak ingin banyak jawaban menghindari masalah dan mengatakan mengejek itu baik karena membuat kode Anda bisa dipermainkan mempromosikan desain yang baik. Namun, secara umum, saya benci berurusan dengan kode yang dipisahkan dengan cara yang tidak memiliki manfaat yang jelas sekarang atau di masa mendatang. Jika Anda tidak memiliki beberapa implementasi sekarang dan tidak mengantisipasi memiliki mereka di masa mendatang, maka IMHO Anda hanya perlu kode keras itu. Ini lebih sederhana dan tidak membosankan klien dengan detail dependensi objek.
dsimcha
5
Namun secara umum, saya benci berurusan dengan kode yang digabungkan dengan cara-cara yang tidak memiliki alasan yang jelas kecuali desain yang buruk. Ini lebih sederhana dan tidak membuat klien bosan dengan fleksibilitas untuk menguji berbagai hal secara terpisah.
S.Lott
3
@ S.Lott: Klarifikasi: Maksud saya kode yang keluar secara signifikan untuk memisahkan hal-hal tanpa menggunakan kasus yang jelas, terutama di mana itu membuat kode atau kode klien secara signifikan lebih bertele-tele, memperkenalkan kelas / antarmuka lain, dll. Tentu saja saya tidak meminta kode untuk lebih erat daripada desain yang paling sederhana dan paling ringkas. Juga, ketika Anda membuat garis abstraksi sebelum waktunya mereka biasanya berakhir di tempat yang salah.
dsimcha
Pertimbangkan memperbarui pertanyaan Anda untuk memperjelas perbedaan apa pun yang Anda buat. Mengintegrasikan urutan komentar itu sulit. Harap perbarui pertanyaan untuk memperjelas dan memfokuskannya.
S.Lott

Jawaban:

116

Ini masalah definisi. Tes dengan dependensi adalah tes integrasi, bukan tes unit. Anda juga harus memiliki suite tes integrasi. Perbedaannya adalah bahwa suite pengujian integrasi dapat dijalankan dalam kerangka pengujian yang berbeda dan mungkin bukan sebagai bagian dari pembuatan karena membutuhkan waktu lebih lama.

Untuk produk kami: Unit test kami dijalankan dengan setiap build, membutuhkan beberapa detik. Subset dari tes integrasi kami berjalan dengan masing-masing check-in, membutuhkan waktu 10 menit. Suite integrasi penuh kami dijalankan setiap malam, membutuhkan waktu 4 jam.

Jeffrey Faust
sumber
4
Jangan lupa tentang tes regresi untuk mencakup bug yang ditemukan dan diperbaiki untuk mencegah reintroduksi ke dalam sistem selama pemeliharaan di masa depan.
RBerteig
2
Saya tidak akan memaksa definisi bahkan jika saya setuju dengan itu. Beberapa kode mungkin memiliki dependensi yang dapat diterima seperti StringFormatter dan masih dianggap oleh sebagian besar unit test.
danidacar
2
danip: definisi yang jelas itu penting, dan saya akan mendesak mereka. Tetapi penting juga untuk menyadari bahwa definisi-definisi itu adalah target. Mereka layak dibidik, tetapi Anda tidak selalu membutuhkan bullseye. Tes unit akan sering memiliki ketergantungan pada perpustakaan tingkat rendah.
Jeffrey Faust
2
Juga penting untuk memahami konsep tes fasad, yang tidak menguji bagaimana komponen saling cocok (seperti tes integrasi) tetapi menguji komponen tunggal secara terpisah. (mis. grafik objek)
Ricardo Rodrigues
1
ini bukan hanya tentang menjadi lebih cepat tetapi juga tentang menjadi sangat membosankan atau tidak terkendali, bayangkan, jika Anda tidak melakukannya, pohon eksekusi Anda yang mengejek mungkin tumbuh secara eksponensial. Bayangkan Anda mengejek 10 dependensi di unit Anda jika Anda mendorong mengejek lebih lanjut, katakanlah 1 dari 10 dependensi digunakan di banyak tempat dan ia memiliki 20 dependensi sendiri, jadi Anda harus mengejek + 20 dependensi lainnya, berpotensi menggandakan di banyak tempat. pada titik api akhir Anda harus mengejek - misalnya database, sehingga Anda tidak perlu mengatur ulang dan itu lebih cepat seperti yang Anda katakan
FantomX1
39

Pengujian dengan semua dependensi yang ada masih penting, tetapi lebih pada ranah pengujian integrasi seperti yang dikatakan Jeffrey Faust.

Salah satu aspek terpenting dari unit testing adalah membuat tes Anda dapat dipercaya. Jika Anda tidak percaya bahwa tes kelulusan benar-benar berarti semuanya baik dan bahwa tes gagal benar-benar berarti masalah dalam kode produksi, tes Anda hampir tidak berguna seperti semula.

Agar tes Anda dapat dipercaya, Anda harus melakukan beberapa hal, tetapi saya akan fokus hanya pada satu untuk jawaban ini. Anda harus memastikan mereka mudah dijalankan, sehingga semua pengembang dapat dengan mudah menjalankannya sebelum memeriksa kode. "Mudah dijalankan" berarti tes Anda berjalan cepat dan tidak ada konfigurasi atau pengaturan yang luas yang diperlukan untuk membuatnya berjalan. Idealnya, siapa pun harus dapat melihat versi terbaru dari kode, menjalankan tes segera, dan melihatnya lulus.

Mengabstraksi ketergantungan pada hal-hal lain (sistem file, database, layanan web, dll.) Memungkinkan Anda untuk menghindari memerlukan konfigurasi dan membuat Anda dan pengembang lainnya kurang rentan terhadap situasi di mana Anda tergoda untuk mengatakan "Oh, tes gagal karena saya tidak "Saya sudah menyiapkan jaringan berbagi. Oh well. Saya akan jalankan nanti."

Jika Anda ingin menguji apa yang Anda lakukan dengan beberapa data, unit Anda menguji kode logika bisnis itu seharusnya tidak peduli bagaimana Anda mendapatkan data itu. Mampu menguji logika inti aplikasi Anda tanpa bergantung pada hal-hal yang mendukung seperti database itu mengagumkan. Jika Anda tidak melakukannya, Anda kehilangan.

PS Saya harus menambahkan bahwa itu pasti mungkin untuk overengineer atas nama testability. Menguji mengemudi aplikasi Anda membantu mengurangi itu. Namun bagaimanapun juga, implementasi pendekatan yang buruk tidak membuat pendekatan tersebut kurang valid. Apa pun dapat disalahgunakan dan dilakukan secara berlebihan jika seseorang tidak terus bertanya "mengapa saya melakukan ini?" saat berkembang.


Sejauh menyangkut ketergantungan internal, keadaan menjadi sedikit berlumpur. Cara saya suka memikirkannya adalah bahwa saya ingin melindungi kelas saya sebanyak mungkin dari perubahan karena alasan yang salah. Jika saya memiliki pengaturan seperti ini ...

public class MyClass 
{
    private SomeClass someClass;
    public MyClass()
    {
        someClass = new SomeClass();
    }

    // use someClass in some way
}

Saya biasanya tidak peduli bagaimana SomeClassdibuat. Saya hanya ingin menggunakannya. Jika SomeClass berubah dan sekarang memerlukan parameter untuk konstruktor ... itu bukan masalah saya. Saya tidak perlu mengubah MyClass untuk mengakomodasi itu.

Sekarang, itu hanya menyentuh pada bagian desain. Sejauh menyangkut tes unit, saya juga ingin melindungi diri dari kelas lain. Jika saya menguji MyClass, saya suka mengetahui fakta bahwa tidak ada dependensi eksternal, bahwa SomeClass pada suatu titik tidak memperkenalkan koneksi database atau beberapa tautan eksternal lainnya.

Tetapi masalah yang lebih besar adalah bahwa saya juga tahu bahwa beberapa hasil metode saya bergantung pada output dari beberapa metode pada SomeClass. Tanpa mengejek / mematikan SomeClass, saya mungkin tidak memiliki cara untuk memvariasikan input yang diminta. Jika saya beruntung, saya mungkin bisa menyusun lingkungan saya di dalam tes sedemikian rupa sehingga akan memicu respons yang tepat dari SomeClass, tetapi dengan cara itu memperkenalkan kompleksitas ke dalam tes saya dan membuatnya rapuh.

Menulis ulang MyClass untuk menerima turunan SomeClass di konstruktor memungkinkan saya untuk membuat turunan palsu dari SomeClass yang mengembalikan nilai yang saya inginkan (baik melalui kerangka kerja mengejek atau dengan tiruan manual). Saya biasanya tidak harus memperkenalkan antarmuka dalam hal ini. Apakah melakukannya atau tidak dalam banyak hal merupakan pilihan pribadi yang mungkin ditentukan oleh bahasa pilihan Anda (mis. Antarmuka lebih mungkin dalam C #, tetapi Anda pasti tidak akan membutuhkannya di Ruby).

Adam Lear
sumber
+1 Jawaban yang bagus, karena ketergantungan eksternal adalah kasus yang tidak saya pikirkan ketika saya menulis pertanyaan awal. Saya telah mengklarifikasi pertanyaan saya sebagai tanggapan. Lihat hasil edit terbaru.
dsimcha
@dsimcha Saya memperluas jawaban saya untuk lebih detail tentang itu. Semoga ini bisa membantu.
Adam Lear
Adam, dapatkah Anda menyarankan bahasa di mana "Jika SomeClass berubah dan sekarang memerlukan parameter untuk konstruktor ... saya tidak harus mengubah MyClass" benar? Maaf, itu hanya melompat keluar pada saya sebagai persyaratan yang tidak biasa. Saya dapat melihat tidak harus mengubah unit test untuk MyClass, tetapi tidak harus mengubah MyClass ... wow.
1
@Moz Yang saya maksudkan adalah bahwa jika cara SomeClass dibuat, MyClass tidak harus berubah jika SomeClass disuntikkan ke dalamnya alih-alih dibuat secara internal. Dalam keadaan normal, MyClass tidak perlu peduli dengan detail pengaturan untuk SomeClass. Jika antarmuka SomeClass berubah, maka ya ... MyClass masih harus dimodifikasi jika ada salah satu metode yang digunakan terpengaruh.
Adam Lear
1
Jika Anda mengejek SomeClass saat menguji MyClass, bagaimana Anda akan mendeteksi jika MyClass menggunakan SomeClass secara tidak benar atau mengandalkan quirk yang tidak teruji dari SomeClass yang mungkin berubah?
beri nama
22

Selain masalah unit vs integrasi, pertimbangkan hal berikut.

Widget Kelas memiliki dependensi pada kelas Thingamajig dan WhatsIt.

Tes unit untuk Widget gagal.

Di kelas mana masalahnya?

Jika Anda menjawab "jalankan debugger" atau "baca kode sampai saya menemukannya", Anda memahami pentingnya menguji hanya unit, bukan dependensi.

Anak sungai
sumber
3
@ Brook: Bagaimana kalau melihat apa hasilnya untuk semua dependensi Widget? Jika semuanya lulus, itu masalah dengan Widget sampai terbukti sebaliknya.
dsimcha
4
@dsimcha, tetapi sekarang Anda menambahkan kompleksitas kembali dalam permainan untuk memeriksa langkah-langkah perantara. Mengapa tidak menyederhanakan dan hanya melakukan tes unit sederhana terlebih dahulu? Kemudian lakukan tes integrasi Anda.
asoundmove
1
@dsimcha, kedengarannya masuk akal sampai Anda masuk ke grafik ketergantungan non-sepele. Katakanlah Anda memiliki objek kompleks yang memiliki kedalaman 3+ lapisan dengan dependensi, ia berubah menjadi pencarian O (N ^ 2) untuk masalah, alih-alih O (1)
Brook
1
Juga, interpretasi saya tentang SRP adalah bahwa sebuah kelas harus memiliki tanggung jawab tunggal pada tingkat domain konseptual / masalah. Tidak masalah jika memenuhi tanggung jawab itu mengharuskannya melakukan banyak hal yang berbeda bila dilihat pada tingkat abstraksi yang lebih rendah. Jika dibawa ke ekstrim SRP akan bertentangan dengan OO karena sebagian besar kelas menyimpan data dan melakukan operasi di atasnya (dua hal bila dilihat pada tingkat yang cukup rendah).
dsimcha
4
@ Brook: Lebih banyak jenis tidak meningkatkan kompleksitas per se. Lebih banyak tipe baik-baik saja jika tipe-tipe itu masuk akal secara konseptual dalam domain masalah dan membuat kode lebih mudah, bukan lebih sulit, untuk dipahami. Masalahnya adalah secara artifisial memisahkan hal-hal yang secara konsep digabungkan pada tingkat masalah domain (yaitu Anda hanya memiliki satu implementasi, mungkin tidak akan pernah memiliki lebih dari satu, dll) dan decoupling tidak memetakan dengan baik untuk konsep domain masalah. Dalam kasus ini adalah konyol, birokratis dan verbal untuk menciptakan abstraksi serius di sekitar implementasi ini.
dsimcha
14

Bayangkan pemrograman itu seperti memasak. Kemudian pengujian unit sama dengan memastikan bahan-bahan Anda segar, enak, dll. Sedangkan pengujian integrasi seperti memastikan makanan Anda lezat.

Pada akhirnya, memastikan bahwa makanan Anda lezat (atau bahwa sistem Anda berfungsi) adalah hal yang paling penting, tujuan akhir. Tetapi jika bahan Anda, maksud saya, unit, bekerja, Anda akan memiliki cara yang lebih murah untuk mengetahuinya.

Memang, jika Anda dapat menjamin bahwa unit / metode Anda berfungsi, Anda cenderung memiliki sistem yang berfungsi. Saya menekankan "lebih mungkin", bukan "pasti". Anda masih memerlukan tes integrasi, sama seperti Anda masih membutuhkan seseorang untuk mencicipi makanan yang Anda masak dan memberi tahu Anda bahwa produk akhirnya baik. Anda akan lebih mudah tiba di sana dengan bahan-bahan segar, itu saja.

Julio
sumber
7
Dan ketika tes integrasi Anda gagal, unit test dapat mengatasi masalah tersebut.
Tim Williscroft
9
Untuk merentang analogi: Ketika Anda merasa bahwa makanan Anda terasa mengerikan, mungkin perlu beberapa penyelidikan untuk menentukan bahwa itu karena roti Anda berjamur. Namun, hasilnya adalah Anda menambahkan unit test untuk memeriksa roti berjamur sebelum dimasak, sehingga masalah khusus itu tidak bisa terjadi lagi. Kemudian jika Anda mengalami kegagalan makan lagi nanti, Anda telah menghilangkan roti berjamur sebagai penyebabnya.
Kyralessa
Cintai analogi ini!
thehowler
6

Unit pengujian dengan mengisolasi mereka sepenuhnya akan memungkinkan untuk menguji SEMUA kemungkinan variasi data dan situasi unit ini dapat diajukan. Karena terisolasi dari yang lain, Anda dapat mengabaikan variasi yang tidak memiliki efek langsung pada unit yang akan diuji. ini pada gilirannya akan sangat mengurangi kerumitan tes.

Pengujian dengan berbagai tingkat dependensi terintegrasi akan memungkinkan Anda untuk menguji skenario tertentu yang mungkin belum diuji dalam unit test.

Keduanya penting. Hanya dengan melakukan pengujian unit, Anda akan selalu mengalami kesalahan yang lebih rumit saat mengintegrasikan komponen. Hanya melakukan pengujian integrasi berarti Anda menguji suatu sistem tanpa keyakinan bahwa bagian-bagian individu dari mesin belum diuji. Untuk berpikir Anda dapat mencapai tes lengkap yang lebih baik hanya dengan melakukan pengujian integrasi hampir mustahil karena semakin banyak komponen yang Anda tambahkan jumlah kombinasi entri tumbuh SANGAT cepat (pikirkan faktorial) dan membuat tes dengan cakupan yang memadai menjadi sangat cepat menjadi sangat mustahil.

Jadi singkatnya, tiga level "unit testing" yang biasanya saya gunakan di hampir semua proyek saya:

  • Tes unit, diisolasi dengan dependensi yang diejek atau di-stub untuk menguji komponen tunggal. Idealnya orang akan mencoba cakupan lengkap.
  • Tes integrasi untuk menguji kesalahan yang lebih halus. Pemeriksaan spot yang dibuat dengan hati-hati yang akan menunjukkan batas kasus dan kondisi umum. Cakupan lengkap seringkali tidak memungkinkan, upaya terfokus pada apa yang akan membuat sistem gagal.
  • Pengujian spesifikasi untuk menyuntikkan berbagai data kehidupan nyata dalam sistem, instrumen data (jika mungkin) dan mengamati output untuk memastikan itu sesuai dengan spesifikasi dan aturan bisnis.

Injeksi ketergantungan adalah salah satu cara yang sangat efisien untuk mencapai ini karena memungkinkan untuk mengisolasi komponen untuk unit test dengan sangat mudah tanpa menambah kompleksitas pada sistem. Skenario bisnis Anda mungkin tidak menjamin penggunaan mekanisme injeksi tetapi skenario pengujian Anda akan melakukannya. Ini bagi saya sudah cukup untuk membuatnya sangat diperlukan. Anda dapat menggunakannya juga untuk menguji berbagai tingkat abstraksi secara mandiri melalui pengujian integrasi parsial.

Newtopian
sumber
4

Apa sisi lain dari ini? Apakah benar-benar penting bahwa unit test tidak juga menguji dependensinya? Jika demikian, mengapa?

Satuan. Berarti tunggal.

Menguji 2 hal berarti Anda memiliki dua hal dan semua dependensi fungsional.

Jika Anda menambahkan hal ke-3, Anda meningkatkan dependensi fungsional dalam tes di luar linear. Interkoneksi di antara hal-hal tumbuh lebih cepat daripada jumlah hal.

Ada n (n-1) / 2 ketergantungan potensial antara n item yang sedang diuji.

Itulah alasan utamanya.

Kesederhanaan memiliki nilai.

S.Lott
sumber
2

Ingat bagaimana Anda pertama kali belajar melakukan rekursi? Prof saya berkata, "Asumsikan Anda memiliki metode yang melakukan x" (misalnya, memecahkan fibbonacci untuk x apa pun). "Untuk menyelesaikan x Anda harus memanggil metode itu untuk x-1 dan x-2". Dalam hal yang sama, mematikan dependensi memungkinkan Anda berpura-pura ada dan menguji apakah unit saat ini melakukan apa yang seharusnya dilakukan. Asumsinya tentu saja bahwa Anda menguji dependensi secara ketat.

Ini pada dasarnya adalah SRP di tempat kerja. Berfokus pada satu tanggung jawab tunggal bahkan untuk pengujian Anda, menghilangkan jumlah juggling mental yang harus Anda lakukan.

Michael Brown
sumber
2

(Ini adalah jawaban kecil. Terima kasih @TimWilliscroft untuk petunjuknya.)

Kesalahan lebih mudah untuk dilokalisasi jika:

  • Baik unit yang diuji dan masing-masing dependensinya diuji secara independen.
  • Setiap tes gagal jika dan hanya jika ada kesalahan dalam kode yang dicakup oleh tes.

Ini bekerja dengan baik di atas kertas. Namun, seperti yang diilustrasikan dalam uraian OP (dependensi bersifat buggy), jika dependensi tidak diuji, akan sulit untuk menentukan lokasi kesalahan.

rwong
sumber
Mengapa dependensi tidak diuji? Mereka mungkin level yang lebih rendah dan lebih mudah untuk unit-test. Selain itu, dengan tes unit yang mencakup kode tertentu, lebih mudah untuk menentukan lokasi kesalahan.
David Thornley
2

Banyak jawaban bagus. Saya juga menambahkan beberapa poin lain:

Pengujian unit juga memungkinkan Anda untuk menguji kode Anda ketika dependensi Anda tidak ada . Misalnya Anda, atau tim Anda, belum menulis lapisan lain, atau mungkin Anda sedang menunggu di antarmuka yang disampaikan oleh perusahaan lain.

Tes unit juga berarti bahwa Anda tidak harus memiliki lingkungan penuh pada mesin dev Anda (mis. Database, server web, dll). Saya kuat akan merekomendasikan bahwa semua pengembang melakukan memiliki lingkungan seperti itu, namun ditebang itu, dalam rangka untuk bug repro dll Namun, jika karena alasan itu tidak mungkin untuk meniru lingkungan produksi maka unit testing setidaknya memberikan yu beberapa tingkat kepercayaan pada kode Anda sebelum masuk ke sistem pengujian yang lebih besar.

Steve
sumber
0

Tentang aspek desain: Saya percaya bahwa proyek kecil pun mendapat manfaat dari membuat kode dapat diuji. Anda tidak perlu harus memperkenalkan sesuatu seperti Guice (kelas pabrik sederhana akan sering melakukannya), tetapi memisahkan proses konstruksi dari hasil logika pemrograman dalam

  • dengan jelas mendokumentasikan dependensi setiap kelas melalui antarmuka itu (sangat membantu bagi orang-orang yang baru dalam tim)
  • kelas-kelas menjadi lebih jelas dan lebih mudah untuk dipertahankan (setelah Anda menempatkan pembuatan objek grafik jelek ke kelas terpisah)
  • kopling longgar (membuat perubahan lebih mudah)
Oliver Weiler
sumber
2
Metode: Ya, tetapi Anda harus menambahkan kode tambahan dan kelas tambahan untuk melakukan ini. Kode harus seringkas mungkin sambil tetap dapat dibaca. IMHO menambahkan pabrik dan yang lainnya overengineering kecuali Anda dapat membuktikan bahwa Anda perlu atau sangat mungkin membutuhkan fleksibilitas yang disediakannya.
dsimcha
0

Uh ... ada poin bagus pada pengujian unit dan integrasi yang ditulis dalam jawaban ini di sini!

Saya melewatkan pandangan terkait biaya dan praktis di sini. Yang mengatakan saya melihat dengan jelas manfaat dari tes unit atom / sangat terisolasi (mungkin sangat independen satu sama lain dan dengan opsi untuk menjalankannya secara paralel dan tanpa dependensi, seperti database, filesystem dll.) Dan tes integrasi (tingkat lebih tinggi), tapi ... itu juga masalah biaya (waktu, uang, ...) dan risiko .

Jadi ada faktor-faktor lain, yang jauh lebih penting (seperti "apa yang harus diuji" ) sebelum Anda memikirkan "cara menguji" dari pengalaman saya ...

Apakah pelanggan saya (secara tidak langsung) membayar biaya penulisan dan perawatan tambahan? Apakah pendekatan yang lebih didorong oleh tes (tulis tes terlebih dahulu sebelum Anda menulis kode) benar-benar hemat biaya di lingkungan saya (risiko kegagalan kode / analisis biaya, orang, spesifikasi desain, pengaturan lingkungan pengujian)? Kode selalu bermasalah, tetapi bisakah biaya lebih efektif untuk memindahkan pengujian ke penggunaan produksi (dalam kasus terburuk!)?

Ini juga sangat tergantung pada apa kualitas kode Anda (standar) atau kerangka kerja, IDE, prinsip-prinsip desain dll. Anda dan tim Anda ikuti dan seberapa berpengalaman mereka. Sebuah kode yang ditulis dengan baik, mudah dimengerti, cukup baik didokumentasikan (idealnya mendokumentasikan diri), modular, ... memperkenalkan bug yang kemungkinan lebih sedikit daripada yang sebaliknya. Jadi "kebutuhan" nyata, tekanan atau biaya pemeliharaan / perbaikan bug / risiko keseluruhan untuk pengujian ekstensif mungkin tidak tinggi.

Mari kita bawa ke ekstrim di mana rekan kerja di tim saya menyarankan, kita harus mencoba untuk menguji unit kode lapisan model Java EE murni kami dengan cakupan 100% yang diinginkan untuk semua kelas di dalam dan mengejek basis data. Atau manajer yang ingin pengujian integrasi dicakup dengan 100% dari semua kasus penggunaan dunia nyata dan alur kerja web ui karena kami tidak ingin mengambil risiko kasus penggunaan apa pun gagal. Tetapi kami memiliki anggaran yang ketat sekitar 1 juta euro, beberapa rencana yang ketat untuk mengkodekan semuanya. Lingkungan pelanggan, di mana bug aplikasi potensial tidak akan menjadi bahaya yang sangat besar bagi manusia atau perusahaan. Aplikasi kami akan diuji secara internal dengan (beberapa) tes unit penting, tes integrasi, tes pelanggan utama dengan rencana uji yang dirancang, fase uji dll. Kami tidak mengembangkan aplikasi untuk beberapa pabrik nuklir atau produksi farmasi!

Saya sendiri mencoba menulis tes jika memungkinkan dan mengembangkan sementara unit menguji kode saya. Tapi saya sering melakukannya dari pendekatan top-down (pengujian integrasi) dan mencoba untuk menemukan titik yang baik, di mana untuk membuat "pemotongan layer aplikasi" untuk tes penting (sering dalam model-layer). (karena sering banyak tentang "lapisan")

Lebih lanjut, unit dan kode uji integrasi tidak datang tanpa dampak negatif pada waktu, uang, pemeliharaan, pengkodean, dll. Ini keren dan harus diterapkan, tetapi dengan hati-hati dan mempertimbangkan implikasi ketika memulai atau setelah 5 tahun dari banyak tes yang dikembangkan kode.

Jadi saya akan mengatakan itu sangat tergantung pada kepercayaan dan biaya / risiko / evaluasi manfaat ... seperti dalam kehidupan nyata di mana Anda tidak bisa dan tidak ingin berlarian dengan banyak atau 100% mekanisme keamanan.

Anak itu bisa dan harus memanjat ke suatu tempat dan mungkin jatuh dan melukai dirinya sendiri. Mobil mungkin berhenti bekerja karena saya mengisi bahan bakar yang salah (input tidak valid :)). Roti bakar dapat terbakar jika tombol waktu berhenti bekerja setelah 3 tahun. Tapi saya tidak, tidak pernah, ingin mengemudi di jalan raya dan memegang setir saya yang terlepas di tangan saya :)

Andreas Dietrich
sumber