Katakanlah saya memiliki fungsi (ditulis dalam Ruby, tetapi harus dapat dimengerti oleh semua orang):
def am_I_old_enough?(name = 'filip')
person = Person::API.new(name)
if person.male?
return person.age > 21
else
return person.age > 18
end
end
Dalam pengujian unit saya akan membuat empat tes untuk mencakup semua skenario. Masing-masing akan menggunakan Person::API
objek mocked dengan metode stubbed male?
dan age
.
Sekarang saatnya menulis tes integrasi. Saya berasumsi bahwa Person :: API tidak boleh diejek lagi. Jadi saya akan membuat empat test case yang persis sama, tetapi tanpa mengejek Person :: objek API. Apakah itu benar?
Jika ya, lalu apa gunanya menulis unit test sama sekali, jika saya hanya bisa menulis tes integrasi yang memberi saya lebih percaya diri (karena saya bekerja pada objek nyata, bukan bertopik atau mengejek)?
unit-testing
testing
ruby
integration-tests
Filip Bartuzi
sumber
sumber
Jawaban:
Tidak, tes integrasi tidak boleh hanya menduplikasi cakupan tes unit. Mereka mungkin menggandakan beberapa liputan, tapi bukan itu intinya.
Inti dari tes unit adalah untuk memastikan bahwa sedikit fungsionalitas tertentu bekerja dengan tepat dan sepenuhnya sebagaimana dimaksud. Sebuah unit test
am_i_old_enough
akan menguji data dengan usia yang berbeda, tentu saja yang dekat dengan ambang batas, kemungkinan semua usia manusia yang terjadi. Setelah Anda menulis tes ini, integritasam_i_old_enough
tidak boleh dipertanyakan lagi.Inti dari tes integrasi adalah untuk memverifikasi bahwa seluruh sistem, atau kombinasi sejumlah besar komponen melakukan hal yang benar ketika digunakan bersama . Pelanggan tidak peduli dengan fungsi utilitas tertentu yang Anda tulis, mereka peduli bahwa aplikasi web mereka diamankan dengan baik terhadap akses oleh anak di bawah umur, karena jika tidak regulator akan memiliki penilaian mereka.
Memeriksa usia pengguna adalah satu bagian kecil dari fungsionalitas itu, tetapi tes integrasi tidak memeriksa apakah fungsi utilitas Anda menggunakan nilai ambang batas yang benar. Ini menguji apakah pemanggil membuat keputusan yang tepat berdasarkan ambang itu, apakah fungsi utilitas dipanggil sama sekali, apakah kondisi lain untuk akses terpenuhi, dll.
Alasan kami membutuhkan kedua jenis tes pada dasarnya adalah bahwa ada kemungkinan kombinasi skenario untuk jalur melalui basis kode yang dapat dilakukan eksekusi. Jika fungsi utilitas memiliki sekitar 100 input yang mungkin, dan ada ratusan fungsi utilitas, maka memeriksa bahwa hal yang benar terjadi dalam semua kasus akan membutuhkan banyak, jutaan kasus uji. Dengan hanya memeriksa semua kasus dalam cakupan yang sangat kecil dan kemudian memeriksa kombinasi umum, relevan, atau kemungkinan untuk cakupan ini, sambil mengasumsikan bahwa cakupan kecil ini sudah benar, seperti yang ditunjukkan oleh pengujian unit , kita bisa mendapatkan penilaian yang cukup percaya diri bahwa sistem sedang melakukan apa yang seharusnya, tanpa tenggelam dalam skenario alternatif untuk diuji.
sumber
The customer doesn't care about a particular utility function you wrote, they care that their web app is properly secured against access by minors
-> Itu pola pikir yang sangat pintar, terima kasih! Masalahnya adalah ketika Anda melakukan proyek untuk diri sendiri. Sulit untuk membagi pola pikir Anda antara menjadi seorang programmer dan menjadi seorang manajer produk pada saat yang samaJawaban singkatnya adalah "Tidak". Bagian yang lebih menarik adalah mengapa / bagaimana situasi ini muncul.
Saya pikir kebingungan ini timbul karena Anda mencoba mematuhi praktik pengujian yang ketat (tes unit vs tes integrasi, mengejek, dll.) Untuk kode yang tampaknya tidak mematuhi praktik ketat.
Itu tidak berarti bahwa kode itu "salah", atau praktik tertentu lebih baik daripada yang lain. Sederhananya bahwa beberapa asumsi yang dibuat oleh praktik pengujian mungkin tidak berlaku dalam situasi ini, dan mungkin membantu untuk menggunakan tingkat "ketat" yang sama dalam praktik pengkodean dan praktik pengujian; atau setidaknya, untuk mengakui bahwa mereka mungkin tidak seimbang, yang akan menyebabkan beberapa aspek menjadi tidak berlaku atau berlebihan.
Alasan paling jelas adalah bahwa fungsi Anda melakukan dua tugas berbeda:
Person
berdasarkan nama mereka. Ini memerlukan pengujian integrasi, untuk memastikannya dapat menemukanPerson
objek yang mungkin dibuat / disimpan di tempat lain.Person
sudah cukup umur, berdasarkan jenis kelamin mereka. Ini membutuhkan pengujian unit, untuk memastikan perhitungan berkinerja seperti yang diharapkan.Dengan mengelompokkan tugas-tugas ini bersama menjadi satu blok kode, Anda tidak dapat menjalankan satu tanpa yang lainnya. Ketika Anda ingin menguji unit perhitungan, Anda dipaksa untuk mencari
Person
(baik dari database nyata atau dari rintisan / mock). Ketika Anda ingin menguji apakah pencarian terintegrasi dengan seluruh sistem, Anda dipaksa untuk juga melakukan perhitungan pada usia. Apa yang harus kita lakukan dengan perhitungan itu? Haruskah kita mengabaikannya, atau memeriksanya? Tampaknya itu adalah kesulitan yang tepat yang Anda gambarkan dalam pertanyaan Anda.Jika kita membayangkan suatu alternatif, kita mungkin memiliki perhitungan sendiri:
Karena ini adalah perhitungan murni, kami tidak perlu melakukan tes integrasi.
Kami juga mungkin tergoda untuk menulis tugas pencarian secara terpisah:
Namun, dalam hal ini fungsinya sangat dekat
Person::API.new
sehingga saya katakan Anda harus menggunakannya (jika nama default diperlukan, apakah lebih baik disimpan di tempat lain, seperti atribut kelas?).Saat menulis tes integrasi untuk
Person::API.new
(atauperson_from_name
) yang perlu Anda perhatikan adalah apakah Anda mendapatkan kembali yang diharapkanPerson
; semua perhitungan berbasis usia diurus di tempat lain, sehingga tes integrasi Anda dapat mengabaikannya.sumber
Poin lain yang saya ingin tambahkan pada jawaban Killian adalah bahwa unit test berjalan sangat cepat, sehingga kita dapat memiliki 1000-an dari mereka. Tes integrasi biasanya memakan waktu lebih lama karena memanggil layanan web, database, atau ketergantungan eksternal lainnya, jadi kami tidak dapat menjalankan tes yang sama (1000-an) untuk skenario integrasi karena akan memakan waktu terlalu lama.
Juga, tes unit biasanya dijalankan pada waktu build (pada mesin build) dan tes integrasi dijalankan setelah penerapan pada lingkungan / mesin.
Biasanya satu akan menjalankan pengujian unit 1000-an kami untuk setiap build, dan kemudian tes integrasi bernilai 100 atau lebih kami setelah setiap penyebaran. Kami mungkin tidak membawa setiap bangunan ke penerapan, tapi itu OK karena build yang kami ambil untuk penerapan tes integrasi akan dijalankan. Biasanya, kami ingin membatasi pengujian ini untuk berjalan dalam 10 atau 15 menit karena kami tidak ingin menahan penyebaran terlalu lama.
Selain itu, pada jadwal mingguan kami dapat menjalankan serangkaian uji integrasi integrasi yang mencakup lebih banyak skenario pada akhir pekan atau waktu henti lainnya. Ini bisa memakan waktu lebih lama dari 15 menit karena lebih banyak skenario akan dibahas, tetapi biasanya tidak ada yang bekerja pada Sat / Sun sehingga kita dapat mengambil lebih banyak waktu dengan tes.
sumber