Bagaimana Anda menguji unit test? [Tutup]

89

Saya menonton siaran web Rob Connerys di Aplikasi MVCStoreFront, dan saya perhatikan dia menguji unit bahkan untuk hal-hal yang paling biasa, seperti:

public Decimal DiscountPrice
{
   get
   {
       return this.Price - this.Discount;
   }
}

Akan ada tes seperti:

[TestMethod]
public void Test_DiscountPrice
{
    Product p = new Product();
    p.Price = 100;
    p.Discount = 20;
    Assert.IsEqual(p.DiscountPrice,80);
}

Sementara, saya semua untuk pengujian unit, terkadang saya bertanya-tanya apakah bentuk pengujian pengembangan pertama ini benar-benar bermanfaat, misalnya, dalam proses nyata, Anda memiliki 3-4 lapisan di atas kode Anda (Permintaan Bisnis, Dokumen Persyaratan, Dokumen Arsitektur) , di mana aturan bisnis yang sebenarnya didefinisikan (Harga Diskon adalah Harga - Diskon) dapat salah didefinisikan.

Jika itu situasinya, pengujian unit Anda tidak berarti apa-apa bagi Anda.

Selain itu, pengujian unit Anda adalah titik kegagalan lainnya:

[TestMethod]
public void Test_DiscountPrice
{
    Product p = new Product();
    p.Price = 100;
    p.Discount = 20;
    Assert.IsEqual(p.DiscountPrice,90);
}

Sekarang tesnya cacat. Jelas dalam pengujian sederhana, ini bukan masalah besar, tetapi katakanlah kami sedang menguji aturan bisnis yang rumit. Apa yang kita dapatkan di sini?

Maju cepat dua tahun dalam kehidupan aplikasi, saat pengembang pemeliharaan memeliharanya. Sekarang bisnis mengubah aturannya, dan pengujian gagal lagi, beberapa pengembang pemula kemudian memperbaiki pengujian dengan tidak benar ... kami sekarang memiliki titik kegagalan lain.

Yang saya lihat adalah lebih banyak kemungkinan kegagalan, tanpa pengembalian yang menguntungkan, jika harga diskon salah, tim penguji masih akan menemukan masalah, bagaimana pengujian unit menyimpan pekerjaan?

Apa yang kulewatkan di sini? Tolong ajari saya untuk mencintai TDD, karena saya kesulitan menerimanya sejauh ini. Saya ingin juga, karena saya ingin tetap progresif, tetapi itu tidak masuk akal bagi saya.

EDIT: Beberapa orang terus menyebutkan bahwa pengujian membantu menegakkan spesifikasi. Menurut pengalaman saya, spesifikasi juga salah, lebih sering daripada tidak, tetapi mungkin saya ditakdirkan untuk bekerja di organisasi di mana spesifikasi ditulis oleh orang-orang yang seharusnya tidak menulis spesifikasi.

FlySwat
sumber
5
dalam banyak kasus, pengujian unit adalah spesifikasi, dan dokumentasinya juga!
Steven A. Lowe
32
... dan kemudian unit tes tes unit dari tes unit ... tapi bagaimana dengan tes unit ^ 4 dan unit ^ 5 tes ... aaaaaaaaahhhhhhhhh!
dacracot
14
Pengujian apa pun dalam jumlah apa pun tidak akan menyelamatkan Anda dari spesifikasi yang salah.
Bill the Lizard
4
Apakah ada orang lain yang baru saja mendengar apa yang terdengar seperti tepukan satu tangan?
gnovice
9
Saya pikir kutipan yang tepat adalah "Itu hanya kura-kura sepanjang jalan."
Quinn Taylor

Jawaban:

63

Pertama, pengujian itu seperti keamanan - Anda tidak akan pernah 100% yakin bahwa Anda sudah mendapatkannya, tetapi setiap lapisan menambahkan lebih banyak kepercayaan diri dan kerangka kerja untuk lebih mudah memperbaiki masalah yang tersisa.

Kedua, Anda dapat memecah pengujian menjadi subrutin yang kemudian dapat diuji sendiri. Jika Anda memiliki 20 pengujian serupa, membuat subrutin (teruji) berarti pengujian utama Anda adalah 20 pemanggilan subrutin sederhana yang kemungkinan besar lebih tepat.

Ketiga, beberapa orang akan berpendapat bahwa TDD menangani masalah ini. Artinya, jika Anda hanya menulis 20 tes dan mereka lulus, Anda tidak sepenuhnya yakin bahwa mereka benar-benar menguji apapun. Tetapi jika setiap pengujian yang Anda tulis awalnya gagal , lalu Anda memperbaikinya, Anda akan jauh lebih yakin bahwa pengujian tersebut benar-benar menguji kode Anda. IMHO bolak-balik ini membutuhkan lebih banyak waktu daripada nilainya, tetapi ini adalah proses yang mencoba mengatasi kekhawatiran Anda.

Jason Cohen
sumber
2
Untuk bermain sebagai pendukung iblis, saya melihat lapisan tambahan sebagai lebih banyak kemungkinan titik kegagalan, yang tidak meningkatkan kepercayaan diri saya. Dalam pekerjaan saya yang sebenarnya, saya bekerja dengan banyak tim di perusahaan SOA yang sangat terdistribusi. Masing-masing tim tersebut dapat membahayakan proyek jika lapisannya gagal.
FlySwat
2
Itulah mengapa Anda menggunakan objek tiruan untuk menguji setiap lapisan secara terpisah.
Toon Krijthe
10
Bagus, jadi pengujian saya akan lulus menggunakan IMockedComplexObject tetapi ketika saya benar-benar menggunakan ComplexObject di dunia nyata, gagal ... Saya tidak mendapatkan apa-apa lagi.
FlySwat
16
@Jonathan - tidak, Anda telah memperoleh keyakinan bahwa kode Anda berfungsi - dengan asumsi bahwa Anda telah mengembangkan antarmuka ComplexObject dan menguji antarmuka tersebut secara memadai. Paling buruk, Anda telah memperoleh pengetahuan bahwa pemahaman Anda tentang ComplexObject tidak seperti yang Anda antisipasi.
tvanfosson
9
@FlySwat: Menanggapi komentar Anda tentang IMockedComplexObject, saya mengutip komentar Cwash pada jawaban lain: "Anda tidak mengejek apa yang Anda coba uji, Anda mengejek apa yang tidak Anda coba uji."
Brian
39

Pengujian yang salah kemungkinan tidak akan merusak kode produksi Anda. Setidaknya, tidak lebih buruk dari tidak ada tes sama sekali. Jadi ini bukan "titik kegagalan": pengujian tidak harus benar agar produk benar-benar berfungsi. Mereka mungkin harus benar sebelum ditandatangani sebagai berfungsi, tetapi proses memperbaiki pengujian yang rusak tidak membahayakan kode implementasi Anda.

Anda dapat menganggap tes, bahkan tes sepele seperti ini, sebagai opini kedua tentang apa yang seharusnya dilakukan kode. Satu pendapat adalah ujian, yang lainnya adalah implementasinya. Jika mereka tidak setuju, Anda tahu bahwa Anda memiliki masalah dan Anda melihat lebih dekat.

Ini juga berguna jika seseorang di masa mendatang ingin menerapkan antarmuka yang sama dari awal. Mereka tidak perlu membaca implementasi pertama untuk mengetahui apa arti Discount, dan pengujian bertindak sebagai cadangan yang tidak ambigu untuk deskripsi tertulis dari antarmuka yang mungkin Anda miliki.

Yang mengatakan, Anda menukar waktu. Jika ada tes lain yang bisa Anda tulis menggunakan waktu yang Anda hemat dengan melewatkan tes sepele ini, mungkin tes itu akan lebih berharga. Itu benar-benar tergantung pada pengaturan pengujian Anda dan sifat aplikasi. Jika Discount penting bagi aplikasi, Anda akan menemukan bug dalam metode ini dalam pengujian fungsional. Semua pengujian unit memungkinkan Anda menangkapnya pada titik Anda menguji unit ini, ketika lokasi kesalahan akan segera terlihat, alih-alih menunggu hingga aplikasi terintegrasi bersama dan lokasi kesalahan mungkin kurang jelas.

Ngomong-ngomong, secara pribadi saya tidak akan menggunakan 100 sebagai harga dalam kasus uji (atau lebih tepatnya, jika saya melakukannya maka saya akan menambahkan tes lain dengan harga lain). Alasannya adalah seseorang di masa depan mungkin berpikir bahwa Diskon seharusnya dalam persentase. Salah satu tujuan dari pengujian sepele seperti ini adalah untuk memastikan bahwa kesalahan dalam membaca spesifikasi dapat dikoreksi.

[Mengenai pengeditan: Saya pikir tidak dapat dihindari bahwa spesifikasi yang salah adalah titik kegagalan. Jika Anda tidak tahu apa yang seharusnya dilakukan aplikasi, kemungkinan besar itu tidak akan melakukannya. Tetapi menulis tes untuk mencerminkan spesifikasi tidak memperbesar masalah ini, itu hanya gagal untuk menyelesaikannya. Jadi Anda tidak menambahkan titik kegagalan baru, Anda hanya merepresentasikan kesalahan yang ada dalam kode alih-alih dokumentasi waffle .]

Steve Jessop
sumber
4
Tes yang salah akan membuat kode rusak menjadi liar. Di situlah kegagalan diperkenalkan. Ini memberikan rasa percaya diri yang salah.
FlySwat
9
Itu benar, tetapi tidak memiliki tes juga memungkinkan kode rusak. Kesalahannya adalah berpikir bahwa jika kode lolos pengujian unit, itu pasti benar - saya sembuh dari itu cukup awal dalam karir saya. Jadi pengujian unit yang rusak tidak membiarkan kode yang rusak keluar, itu hanya memungkinkannya untuk pengujian integrasi.
Steve Jessop
7
Selain itu, pengujian yang salah pun dapat menangkap kode yang rusak, asalkan mengandung kesalahan yang berbeda dari penerapannya. Itulah poin saya bahwa tes tidak mutlak harus benar, tes itu ada untuk menarik perhatian Anda ke area yang menjadi perhatian.
Steve Jessop
2
jawaban yang sangat menarik.
Peter
22

Yang saya lihat adalah lebih banyak kemungkinan kegagalan, tanpa pengembalian yang menguntungkan, jika harga diskon salah, tim penguji masih akan menemukan masalah, bagaimana pengujian unit menyimpan pekerjaan?

Pengujian unit tidak seharusnya menghemat pekerjaan, ini seharusnya membantu Anda menemukan dan mencegah bug. Ini lebih banyak pekerjaan, tetapi ini jenis pekerjaan yang tepat. Ini memikirkan kode Anda pada tingkat perincian terendah dan menulis kasus uji yang membuktikan bahwa ia berfungsi dalam kondisi yang diharapkan , untuk sekumpulan masukan tertentu. Ini mengisolasi variabel sehingga Anda dapat menghemat waktu dengan mencari di tempat yang tepat ketika bug muncul dengan sendirinya. Ini menyimpan rangkaian pengujian tersebut sehingga Anda dapat menggunakannya berulang kali saat Anda harus membuat perubahan di masa mendatang.

Saya pribadi berpikir bahwa sebagian besar metodologi tidak banyak langkah yang dihapus dari rekayasa perangkat lunak kultus kargo , termasuk TDD, tetapi Anda tidak harus mematuhi TDD yang ketat untuk menuai manfaat dari pengujian unit. Pertahankan bagian yang baik dan buang bagian yang menghasilkan sedikit manfaat.

Akhirnya, jawaban atas pertanyaan tituler Anda " Bagaimana Anda menguji unit test? " Adalah bahwa Anda tidak perlu melakukannya. Setiap tes unit harus benar-benar mati otak. Panggil metode dengan masukan tertentu dan bandingkan dengan keluaran yang diharapkan. Jika spesifikasi untuk suatu metode berubah maka Anda dapat mengharapkan bahwa beberapa pengujian unit untuk metode itu juga perlu diubah. Itulah salah satu alasan mengapa Anda melakukan pengujian unit pada tingkat perincian yang rendah, jadi hanya beberapa pengujian unit yang harus diubah. Jika Anda menemukan bahwa pengujian untuk banyak metode berbeda berubah untuk satu perubahan dalam persyaratan, Anda mungkin tidak menguji pada tingkat perincian yang cukup baik.

Bill the Lizard
sumber
"Panggil metode dengan masukan tertentu dan bandingkan dengan keluaran yang diharapkan." tetapi bagaimana jika hasilnya adalah tipe yang kompleks ... seperti dokumen XML. Anda tidak bisa hanya "==", Anda harus menulis perbandingan kode tertentu, dan mungkin metode perbandingan Anda bisa bermasalah ??
andy
@andy: Anda harus menguji metode perbandingan Anda secara terpisah. Setelah Anda benar-benar mengujinya, Anda dapat mengandalkannya untuk bekerja di tes lain.
Bill the Lizard
keren, terima kasih Bill. Saya mulai bekerja di tempat baru, dan ini pertama kalinya saya mengikuti Pengujian Unit. Saya pikir pada prinsipnya itu berfungsi, dan kami menggunakan Cruise Control di mana itu sangat berguna, tetapi serangkaian besar pengujian tampaknya mengalami nasib yang sama dengan kode warisan ... Saya hanya tidak yakin tentang itu ....
andy
11

Tes unit ada sehingga unit Anda (metode) melakukan apa yang Anda harapkan. Menulis tes terlebih dahulu memaksa Anda untuk memikirkan tentang apa yang Anda harapkan sebelum Anda menulis kode. Berpikir sebelum melakukan selalu merupakan ide yang bagus.

Tes unit harus mencerminkan aturan bisnis. Memang, mungkin ada kesalahan dalam kode, tetapi menulis tes terlebih dahulu memungkinkan Anda menulisnya dari perspektif aturan bisnis sebelum kode apa pun ditulis. Menulis tes setelahnya, menurut saya, lebih cenderung mengarah pada kesalahan yang Anda gambarkan karena Anda tahu bagaimana kode mengimplementasikannya dan tergoda hanya untuk memastikan bahwa implementasinya benar - bukan maksudnya benar.

Juga, tes unit hanya satu bentuk - dan yang terendah, pada - tes yang harus Anda tulis. Tes integrasi dan tes penerimaan juga harus ditulis, yang terakhir oleh pelanggan, jika mungkin, untuk memastikan bahwa sistem beroperasi seperti yang diharapkan. Jika Anda menemukan kesalahan selama pengujian ini, kembali dan tulis pengujian unit (yang gagal) untuk menguji perubahan fungsionalitas agar berfungsi dengan benar, lalu ubah kode Anda agar pengujian berhasil. Sekarang Anda memiliki uji regresi yang merekam perbaikan bug Anda.

[EDIT]

Hal lain yang saya temukan dengan melakukan TDD. Ini hampir memaksa desain yang bagus secara default. Ini karena desain yang sangat berpasangan hampir tidak mungkin untuk pengujian unit secara terpisah. Tidak butuh waktu lama menggunakan TDD untuk mengetahui bahwa menggunakan antarmuka, inversi kontrol, dan injeksi ketergantungan - semua pola yang akan meningkatkan desain Anda dan mengurangi kopling - sangat penting untuk kode yang dapat diuji.

tvanfosson.dll
sumber
Mungkin di sinilah letak masalah saya. Saya dapat memvisualisasikan algoritme untuk aturan bisnis dengan lebih mudah daripada saya dapat memvisualisasikan hasilnya, jadi saya tidak memiliki masalah dalam mengimplementasikan kode itu sendiri, tetapi menganggap mengejek aturan sebagai hal yang berlebihan. Mungkin hanya itu yang kupikirkan.
FlySwat
Itulah yang Anda lakukan dalam pengujian unit. Pecahkan algoritme itu menjadi beberapa bagian dan periksa setiap bagian. Biasanya, saya menemukan bahwa kode saya menulis sendiri karena saya telah menulis ekspektasi dalam pengujian unit saya.
tvanfosson
Mock adalah istilah yang kelebihan beban di ruang pengujian. Anda tidak mengejek apa yang Anda coba uji, Anda mengejek apa yang tidak Anda coba uji ... Saat Anda menulis ujian untuk aturan bisnis Anda, Anda membuat kode yang menjalankannya - itu tidak mengejek sama sekali .
cwash
@cwash - Saya tidak yakin bagaimana komentar Anda berlaku untuk jawaban saya. Saya tidak menyebutkan mengejek ... dan saya setuju dengan pengamatan Anda.
tvanfosson
@tvanfosson - komentar terakhir saya adalah sebagai tanggapan atas @FlySwat "... mengejek aturan sebagai mubazir." Maaf saya lupa menentukan.
cwash
10

Bagaimana seseorang menguji sebuah tes ? Pengujian mutasi adalah teknik berharga yang secara pribadi saya gunakan untuk memberikan efek yang sangat bagus. Baca artikel yang ditautkan untuk lebih jelasnya, dan tautkan ke lebih banyak referensi akademis, tetapi secara umum artikel itu "menguji tes Anda" dengan memodifikasi kode sumber Anda (misalnya, mengubah "x + = 1" menjadi "x - = 1") dan kemudian menjalankan kembali pengujian Anda, memastikan bahwa setidaknya satu pengujian gagal. Setiap mutasi yang tidak menyebabkan kegagalan pengujian akan ditandai untuk penyelidikan nanti.

Anda akan terkejut melihat bagaimana Anda dapat memiliki 100% jangkauan garis dan cabang dengan serangkaian tes yang terlihat komprehensif, namun Anda dapat secara fundamental mengubah atau bahkan mengomentari baris dalam sumber Anda tanpa ada tes yang mengeluh. Seringkali ini berujung pada tidak menguji dengan input yang tepat untuk mencakup semua kasus batas, terkadang lebih halus, tetapi dalam semua kasus saya terkesan dengan seberapa banyak hasilnya.

Andrzej Doyle
sumber
1
+1 konsep menarik yang belum saya dengar
Wim Coenen
9

Saat menerapkan Test-Driven Development (TDD), yang dimulai dengan tes yang gagal . Langkah ini, yang mungkin tampak tidak perlu, sebenarnya ada di sini untuk memverifikasi pengujian unit sedang menguji sesuatu. Memang, jika tes tidak pernah gagal, itu tidak membawa nilai dan lebih buruk lagi, mengarah pada kepercayaan yang salah karena Anda akan mengandalkan hasil positif yang tidak membuktikan apa pun.

Ketika mengikuti proses ini secara ketat, semua '' unit '' dilindungi oleh jaring pengaman yang dibuat oleh unit test, bahkan yang paling biasa.

Assert.IsEqual(p.DiscountPrice,90);

Tidak ada alasan tes berkembang ke arah itu - atau saya kehilangan sesuatu dalam alasan Anda. Jika harga 100 dan diskon 20, harga diskon 80. Ini seperti invarian.

Sekarang bayangkan perangkat lunak Anda perlu mendukung jenis diskon lain berdasarkan persentase, mungkin tergantung pada volume yang dibeli, metode Product :: DiscountPrice () Anda mungkin menjadi lebih rumit. Dan mungkin saja memperkenalkan perubahan tersebut melanggar aturan diskon sederhana yang kami miliki pada awalnya. Kemudian Anda akan melihat nilai tes ini yang akan segera mendeteksi regresi.


Merah - Hijau - Refactor - ini untuk mengingat esensi dari proses TDD.

Merah mengacu pada bilah merah JUnit saat pengujian gagal.

Hijau adalah warna bilah kemajuan JUnit ketika semua tes lulus.

Refactor dalam kondisi hijau: hapus duplikasi apa pun, tingkatkan keterbacaan.


Sekarang untuk membahas maksud Anda tentang "3-4 lapisan di atas kode", ini benar dalam proses tradisional (seperti air terjun), bukan saat proses pengembangan gesit. Dan tangkas adalah dunia tempat TDD berasal; TDD adalah dasar dari eXtreme Programming .

Agile adalah tentang komunikasi langsung daripada dokumen persyaratan yang dilemparkan ke dinding.

dermawan
sumber
8

Sementara, saya semua untuk pengujian unit, terkadang saya bertanya-tanya apakah bentuk pengujian pengembangan pertama ini benar-benar bermanfaat ...

Tes kecil dan sepele seperti ini bisa menjadi "burung kenari di tambang batu bara" untuk basis kode Anda, memperingatkan bahaya sebelum terlambat. Tes-tes sepele berguna untuk dilakukan karena membantu Anda mendapatkan interaksi yang benar.

Misalnya, pikirkan tentang pengujian sepele yang dilakukan untuk menyelidiki cara menggunakan API yang tidak Anda kenal. Jika pengujian tersebut memiliki relevansi dengan apa yang Anda lakukan dalam kode yang menggunakan API "nyata", ada gunanya untuk tetap mempertahankan pengujian tersebut. Saat API merilis versi baru dan Anda perlu mengupgrade. Sekarang Anda memiliki asumsi tentang bagaimana Anda mengharapkan API berperilaku yang direkam dalam format yang dapat dieksekusi yang dapat Anda gunakan untuk menangkap regresi.

... [Dalam proses yang sebenarnya, Anda memiliki 3-4 lapisan di atas kode Anda (Permintaan Bisnis, Dokumen Persyaratan, Dokumen Arsitektur), di mana aturan bisnis yang sebenarnya didefinisikan (Harga Diskon adalah Harga - Diskon) dapat salah didefinisikan. Jika itu situasinya, tes unit Anda tidak berarti apa-apa bagi Anda.

Jika Anda telah membuat kode selama bertahun-tahun tanpa tes tertulis, mungkin tidak langsung terlihat jelas bagi Anda bahwa ada nilainya. Namun jika Anda memiliki pola pikir bahwa cara terbaik untuk bekerja adalah "rilis lebih awal, sering rilis" atau "gesit" karena Anda menginginkan kemampuan untuk menerapkan dengan cepat / terus-menerus, maka pengujian Anda pasti berarti. Satu-satunya cara untuk melakukannya adalah dengan melegitimasi setiap perubahan yang Anda buat pada kode dengan tes. Tidak peduli seberapa kecil tesnya, setelah Anda memiliki rangkaian pengujian hijau, Anda secara teoritis dapat menerapkannya. Lihat juga "produksi berkelanjutan" dan "beta abadi".

Anda juga tidak harus menjadi "ujian pertama" untuk memiliki pola pikir ini, tetapi itu biasanya cara paling efisien untuk sampai ke sana. Ketika Anda melakukan TDD, Anda mengunci diri Anda ke dalam siklus Refactor Merah Hijau kecil dua sampai tiga menit. Anda tidak dapat berhenti dan pergi dan memiliki kekacauan total di tangan Anda yang akan memakan waktu satu jam untuk debug dan disatukan kembali.

Selain itu, pengujian unit Anda adalah titik kegagalan lainnya ...

Tes yang berhasil adalah tes yang menunjukkan kegagalan dalam sistem. Tes yang gagal akan memperingatkan Anda akan kesalahan dalam logika tes atau dalam logika sistem Anda. Tujuan pengujian Anda adalah untuk memecahkan kode Anda atau membuktikan satu skenario berfungsi.

Jika Anda menulis tes setelah kode, Anda berisiko menulis tes yang "buruk" karena untuk melihat bahwa tes Anda benar-benar berfungsi, Anda perlu melihatnya rusak dan berfungsi. Saat Anda menulis pengujian setelah kode, ini berarti Anda harus "membuka perangkap" dan memasukkan bug ke dalam kode untuk melihat pengujian gagal. Sebagian besar pengembang tidak hanya merasa tidak nyaman dengan hal ini, tetapi juga akan membantah bahwa ini hanya membuang-buang waktu.

Apa yang kita dapatkan di sini?

Pasti ada manfaatnya melakukan sesuatu dengan cara ini. Michael Feathers mendefinisikan "kode warisan" sebagai "kode yang belum diuji." Saat Anda mengambil pendekatan ini, Anda melegitimasi setiap perubahan yang Anda buat pada basis kode Anda. Ini lebih ketat daripada tidak menggunakan pengujian, tetapi ketika harus mempertahankan basis kode yang besar, itu membayar sendiri.

Berbicara tentang Feathers, ada dua sumber bagus yang harus Anda periksa sehubungan dengan ini:

Keduanya menjelaskan cara menerapkan jenis praktik dan disiplin ini ke dalam proyek yang bukan "Greenfield". Mereka menyediakan teknik untuk menulis tes seputar komponen yang berpasangan erat, ketergantungan kabel, dan hal-hal yang tidak perlu Anda kendalikan. Ini semua tentang menemukan "jahitan" dan menguji sekelilingnya.

[Jika harga diskon salah, tim penguji masih akan menemukan masalah, bagaimana pengujian unit menyimpan pekerjaan?

Kebiasaan seperti ini seperti investasi. Pengembalian tidak langsung; mereka membangun seiring waktu. Alternatif untuk tidak menguji pada dasarnya mengambil hutang karena tidak dapat menangkap regresi, memperkenalkan kode tanpa takut akan kesalahan integrasi, atau mendorong keputusan desain. Keindahannya adalah Anda melegitimasi setiap perubahan yang dimasukkan ke dalam basis kode Anda.

Apa yang kulewatkan di sini? Tolong ajari saya untuk mencintai TDD, karena saya kesulitan menerimanya sejauh ini. Saya ingin juga, karena saya ingin tetap progresif, tetapi itu tidak masuk akal bagi saya.

Saya melihatnya sebagai tanggung jawab profesional. Itu ideal untuk diperjuangkan. Tetapi sangat sulit untuk diikuti dan membosankan. Jika Anda peduli, dan merasa Anda tidak seharusnya menghasilkan kode yang tidak diuji, Anda akan dapat menemukan kekuatan kemauan untuk mempelajari kebiasaan pengujian yang baik. Satu hal yang banyak saya lakukan sekarang (seperti yang dilakukan orang lain) adalah mengatur waktu sendiri satu jam untuk menulis kode tanpa tes sama sekali, kemudian memiliki disiplin untuk membuangnya. Ini mungkin tampak sia-sia, tetapi sebenarnya tidak. Ini tidak seperti latihan yang merugikan materi fisik perusahaan. Ini membantu saya untuk memahami masalah dan cara menulis kode sedemikian rupa sehingga memiliki kualitas yang lebih tinggi dan dapat diuji.

Saran saya pada akhirnya adalah jika Anda benar-benar tidak memiliki keinginan untuk menjadi ahli dalam hal itu, maka jangan lakukan itu sama sekali. Tes buruk yang tidak dipertahankan, tidak berkinerja baik, dll. Bisa lebih buruk daripada tidak memiliki tes apa pun. Sulit untuk belajar sendiri, dan Anda mungkin tidak akan menyukainya, tetapi hampir tidak mungkin untuk mempelajarinya jika Anda tidak memiliki keinginan untuk melakukannya, atau tidak dapat melihat nilai yang cukup di dalamnya. menjamin investasi waktu.

Beberapa orang terus menyebutkan bahwa pengujian membantu menegakkan spesifikasi. Menurut pengalaman saya, spesifikasi juga salah, lebih sering daripada tidak ...

Keyboard pengembang adalah tempat pertemuan karet dengan jalan. Jika speknya salah dan Anda tidak mengibarkan bendera di atasnya, kemungkinan besar Anda akan disalahkan karenanya. Atau setidaknya kode Anda akan. Disiplin dan ketelitian yang terlibat dalam pengujian sulit untuk ditaati. Itu sama sekali tidak mudah. Itu membutuhkan latihan, banyak pembelajaran dan banyak kesalahan. Tapi akhirnya itu membuahkan hasil. Pada proyek yang bergerak cepat dan cepat berubah, itulah satu-satunya cara Anda dapat tidur di malam hari, tidak peduli jika itu memperlambat Anda.

Hal lain yang perlu dipikirkan di sini adalah bahwa teknik yang pada dasarnya sama dengan pengujian telah terbukti berhasil di masa lalu: "ruang bersih" dan "desain berdasarkan kontrak" keduanya cenderung menghasilkan jenis konstruksi kode "meta" yang sama yang tes dilakukan, dan menerapkannya pada titik yang berbeda. Tak satu pun dari teknik ini adalah peluru perak, dan ketelitian pada akhirnya akan merugikan Anda dalam cakupan fitur yang dapat Anda berikan dalam hal waktu ke pasar. Tapi bukan itu masalahnya. Ini tentang mampu mempertahankan apa yang Anda berikan. Dan itu sangat penting untuk sebagian besar proyek.

cwash
sumber
7

Pengujian unit bekerja sangat mirip dengan pembukuan entri ganda. Anda menyatakan hal yang sama (aturan bisnis) dalam dua cara yang sangat berbeda (seperti aturan yang diprogram dalam kode produksi Anda, dan sebagai contoh sederhana, representatif dalam pengujian Anda). Sangat tidak mungkin Anda membuat kesalahan yang sama pada keduanya, jadi jika mereka berdua setuju satu sama lain, kecil kemungkinan Anda salah.

Bagaimana pengujian akan sepadan dengan usahanya? Dalam pengalaman saya setidaknya dalam empat cara, setidaknya saat melakukan pengembangan yang digerakkan oleh pengujian:

  • ini membantu Anda menghasilkan desain yang dipisahkan dengan baik. Anda hanya dapat menguji kode unit yang dipisahkan dengan baik;
  • ini membantu Anda menentukan kapan Anda selesai. Harus menentukan perilaku yang diperlukan dalam pengujian membantu untuk tidak membangun fungsionalitas yang sebenarnya tidak Anda butuhkan, dan menentukan kapan fungsionalitas tersebut selesai;
  • ini memberi Anda jaring pengaman untuk refactorings, yang membuat kode lebih bisa menerima perubahan; dan
  • ini menghemat banyak waktu debugging, yang sangat mahal (saya pernah mendengar perkiraan bahwa secara tradisional, pengembang menghabiskan hingga 80% dari waktu debugging).
Ilja Preuß
sumber
5

Sebagian besar pengujian unit, menguji asumsi. Dalam hal ini, harga diskon haruslah harga dikurangi diskon. Jika asumsi Anda salah, saya yakin kode Anda juga salah. Dan jika Anda membuat kesalahan konyol, tes akan gagal dan Anda akan memperbaikinya.

Jika aturan berubah, pengujian akan gagal dan itu hal yang baik. Jadi, Anda juga harus mengubah tes dalam kasus ini.

Sebagai aturan umum, jika pengujian langsung gagal (dan Anda tidak menggunakan desain pertama pengujian), pengujian atau kodenya salah (atau keduanya jika Anda mengalami hari yang buruk). Anda menggunakan akal sehat (dan memiliki spesifikasi) untuk memperbaiki kode yang melanggar dan menjalankan kembali tes.

Seperti yang dikatakan Jason, pengujian adalah keamanan. Dan ya, terkadang mereka memperkenalkan pekerjaan tambahan karena tes yang salah. Tetapi sebagian besar waktu mereka adalah penabung waktu yang sangat besar. (Dan Anda memiliki kesempatan sempurna untuk menghukum orang yang melanggar ujian (kita berbicara tentang ayam karet)).

Toon Krijthe
sumber
4

Uji semua yang Anda bisa. Bahkan kesalahan sepele, seperti lupa mengubah meter menjadi kaki dapat menimbulkan efek samping yang sangat mahal. Tulis tes, tulis kode untuk diperiksa, lakukan lulus, lanjutkan. Siapa tahu suatu saat nanti, seseorang bisa saja mengganti kode diskonnya. Tes dapat mendeteksi masalah.

Jim C
sumber
Itu tidak menjawab semua pikiranku. Saya memahami mantra dasar TDD ... Saya tidak melihat manfaatnya.
FlySwat
4

Saya melihat pengujian unit dan kode produksi memiliki hubungan simbiosis. Sederhananya: yang satu menguji yang lain. Dan keduanya menguji pengembang.

Johnsyweb
sumber
3

Ingatlah bahwa biaya perbaikan cacat meningkat (secara eksponensial) karena cacat tersebut hidup selama siklus pengembangan. Ya, tim penguji mungkin menemukan cacat, tetapi (biasanya) akan membutuhkan lebih banyak pekerjaan untuk mengisolasi dan memperbaiki cacat dari titik itu daripada jika pengujian unit gagal, dan akan lebih mudah untuk memperkenalkan cacat lain saat memperbaikinya jika Anda tidak memiliki pengujian unit untuk dijalankan.

Itu biasanya lebih mudah dilihat dengan sesuatu yang lebih dari sekadar contoh sepele ... dan dengan contoh yang sepele, nah, jika Anda entah bagaimana mengacaukan pengujian unit, orang yang meninjaunya akan menangkap kesalahan dalam pengujian atau kesalahan dalam kode, atau kedua. (Mereka sedang ditinjau, bukan?) Seperti yang ditunjukkan oleh tvanfosson , pengujian unit hanyalah salah satu bagian dari rencana SQA.

Dalam arti tertentu, tes unit adalah asuransi. Mereka bukan jaminan bahwa Anda akan menemukan setiap cacat, dan terkadang Anda tampak menghabiskan banyak sumber daya untuk itu, tetapi ketika mereka menemukan cacat yang dapat Anda perbaiki, Anda akan menghabiskan lebih sedikit dibandingkan jika Anda tidak memiliki pengujian sama sekali dan harus memperbaiki semua cacat di bagian hilir.

Dave DuPlantis
sumber
3

Saya mengerti maksud Anda, tetapi itu jelas-jelas dilebih-lebihkan.

Argumen Anda pada dasarnya adalah: Ujian memperkenalkan kegagalan. Oleh karena itu tes itu buruk / buang-buang waktu.

Meskipun itu mungkin benar dalam beberapa kasus, itu bukan mayoritas.

TDD mengasumsikan: Lebih Banyak Tes = Lebih Sedikit Kegagalan.

Tes lebih mungkin untuk menangkap titik kegagalan daripada memperkenalkannya.

sinar
sumber
1

Lebih banyak otomatisasi dapat membantu di sini! Ya, menulis tes unit bisa sangat merepotkan, jadi gunakan beberapa alat untuk membantu Anda. Lihatlah sesuatu seperti Pex, dari Microsoft, jika Anda menggunakan .Net Ini secara otomatis akan membuat rangkaian pengujian unit untuk Anda dengan memeriksa kode Anda. Ini akan menghasilkan tes yang memberikan cakupan yang baik, mencoba untuk mencakup semua jalur melalui kode Anda.

Tentu saja, hanya dengan melihat kode Anda, ia tidak dapat mengetahui apa yang sebenarnya Anda coba lakukan, jadi ia tidak tahu apakah itu benar atau tidak. Tapi, itu akan menghasilkan kasus pengujian yang menarik untuk Anda, dan Anda kemudian dapat memeriksanya dan melihat apakah itu berperilaku seperti yang Anda harapkan.

Jika Anda kemudian melangkah lebih jauh dan menulis pengujian unit berparameter (Anda dapat menganggap ini sebagai kontrak, sebenarnya) itu akan menghasilkan kasus pengujian khusus dari ini, dan kali ini dapat mengetahui apakah ada yang salah, karena pernyataan Anda dalam pengujian Anda akan gagal.


sumber
1

Saya telah memikirkan sedikit tentang cara yang baik untuk menjawab pertanyaan ini, dan ingin menarik kesejajaran dengan metode ilmiah. IMO, Anda dapat mengubah pertanyaan ini, "Bagaimana Anda melakukan percobaan?"

Eksperimen memverifikasi asumsi empiris (hipotesis) tentang alam semesta fisik. Pengujian unit akan menguji asumsi tentang status atau perilaku kode yang mereka panggil. Kita dapat berbicara tentang validitas eksperimen, tetapi itu karena kami tahu, melalui banyak eksperimen lain, bahwa ada sesuatu yang tidak sesuai. Itu tidak memiliki validitas konvergen dan bukti empiris . Kami tidak merancang eksperimen baru untuk menguji atau memverifikasi validitas eksperimen , tetapi kami mungkin merancang eksperimen yang benar-benar baru .

Jadi seperti eksperimen , kami tidak mendeskripsikan validitas pengujian unit berdasarkan lulus atau tidaknya pengujian unit itu sendiri. Bersamaan dengan pengujian unit lainnya, ini menjelaskan asumsi yang kami buat tentang sistem yang sedang diuji. Juga, seperti eksperimen, kami mencoba menghilangkan kerumitan sebanyak mungkin dari apa yang kami uji. "Sesederhana mungkin, tapi tidak lebih sederhana."

Tidak seperti eksperimen , kami memiliki trik untuk memverifikasi pengujian kami valid selain hanya validitas konvergen. Kami dengan cerdik dapat memperkenalkan bug yang kami tahu harus ditangkap oleh pengujian, dan melihat apakah pengujian tersebut memang gagal. (Seandainya saja kita bisa melakukannya di dunia nyata, kita tidak akan terlalu bergantung pada validitas konvergen ini!) Cara yang lebih efisien untuk melakukan ini adalah melihat pengujian Anda gagal sebelum menerapkannya (langkah merah di Merah, Hijau, Refactor ).

cwash
sumber
1

Anda perlu menggunakan paradigma yang benar saat menulis tes.

  1. Mulailah dengan menulis tes Anda terlebih dahulu.
  2. Pastikan mereka gagal untuk memulai.
  3. Suruh mereka lewat.
  4. Peninjauan kode sebelum Anda memasukkan kode Anda (pastikan tes ditinjau.)

Anda tidak selalu bisa memastikan tetapi mereka meningkatkan tes secara keseluruhan.

Jonathan
sumber
0

Meskipun Anda tidak menguji kode Anda, itu pasti akan diuji dalam produksi oleh pengguna Anda. Pengguna sangat kreatif dalam mencoba merusak perangkat lunak Anda dan menemukan bahkan kesalahan yang tidak kritis.

Memperbaiki bug dalam produksi jauh lebih mahal daripada menyelesaikan masalah dalam fase pengembangan. Sebagai efek sampingnya, Anda akan kehilangan pendapatan karena eksodus pelanggan. Anda dapat mengandalkan 11 pelanggan yang hilang atau tidak didapat untuk 1 pelanggan yang marah.


sumber