Apakah tes integrasi dimaksudkan untuk mengulang semua tes unit?

36

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::APIobjek 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)?

Filip Bartuzi
sumber
3
Nah, salah satu poinnya adalah, bahwa dengan mengejek / mengujinya, Anda dapat mengisolasi masalah apa pun pada kode Anda. Jika tes integrasi gagal, Anda tidak mengetahui kode siapa yang rusak, milik Anda, atau API.
Chris Wohlert
9
Hanya empat tes? Anda memiliki enam batas usia yang harus Anda uji: 17, 18, 19, 20, 21, 22 ...;)
David Arno
22
@FilipBartuzi, saya menganggap metode ini memeriksa apakah seorang pria lebih dari 21 misalnya? Seperti yang ditulis saat ini, itu tidak melakukan itu, hanya benar jika mereka 22+. "Lebih dari 21" dalam bahasa Inggris berarti "21+". Jadi ada bug dalam kode Anda. Bug tersebut ditangkap dengan menguji nilai batas, yaitu 20, 21, 22 untuk laki-laki, 17,18,19 untuk perempuan dalam kasus ini. Jadi setidaknya diperlukan enam tes.
David Arno
6
Belum lagi kasus 0 dan -1. Apa artinya seseorang berusia -1 tahun? Apa yang harus dilakukan kode Anda jika API Anda mengembalikan sesuatu yang tidak masuk akal?
RubberDuck
9
Ini akan jauh lebih mudah untuk diuji jika Anda melewatkan objek seseorang sebagai parameter.
JeffO

Jawaban:

72

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_enoughakan menguji data dengan usia yang berbeda, tentu saja yang dekat dengan ambang batas, kemungkinan semua usia manusia yang terjadi. Setelah Anda menulis tes ini, integritas am_i_old_enoughtidak 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.

Kilian Foth
sumber
6
"Kita bisa mendapatkan penilaian yang cukup percaya diri bahwa sistem melakukan apa yang seharusnya, tanpa tenggelam dalam skenario alternatif untuk diuji." Terima kasih. Saya suka ketika seseorang mendekati pengujian otomatis dengan kewarasan.
jpmc26
1
JB Rainsberger berbicara tentang tes dan ledakan kombinasi yang Anda tulis di paragraf terakhir, yang disebut "Tes Terpadu Are A Scam" . Ini bukan soal tes integrasi, tapi masih cukup menarik.
Bart van Nierop
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 sama
Filip Bartuzi
14

Jawaban 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:

  • Mencari Personberdasarkan nama mereka. Ini memerlukan pengujian integrasi, untuk memastikannya dapat menemukan Personobjek yang mungkin dibuat / disimpan di tempat lain.
  • Menghitung apakah a Personsudah 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:

def is_old_enough?(person)
   if person.male?
      return person.age > 21
   else 
      return person.age > 18
   end
end

Karena ini adalah perhitungan murni, kami tidak perlu melakukan tes integrasi.

Kami juga mungkin tergoda untuk menulis tugas pencarian secara terpisah:

def person_from_name(name = 'filip')
   return Person::API.new(name)
end

Namun, dalam hal ini fungsinya sangat dekat Person::API.newsehingga 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(atau person_from_name) yang perlu Anda perhatikan adalah apakah Anda mendapatkan kembali yang diharapkan Person; semua perhitungan berbasis usia diurus di tempat lain, sehingga tes integrasi Anda dapat mengabaikannya.

Warbo
sumber
11

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.

Jon Raynor
sumber
tidak berlaku untuk bahasa dinamis (yaitu tanpa tahap bangun)
Filip Bartuzi