Unit menguji klien dan pembungkus API

14

Saya telah berputar-putar mencoba mencari cara terbaik untuk menguji unit perpustakaan klien API yang saya kembangkan. Perpustakaan memiliki Clientkelas yang pada dasarnya memiliki pemetaan 1: 1 dengan API, dan Wrapperkelas tambahan yang menyediakan antarmuka yang lebih ramah pengguna dari atas Client.

Wrapper --> Client --> External API

Saya pertama kali menulis banyak pengujian terhadap keduanya Clientdan Wrapper, secara efektif hanya menguji bahwa mereka meneruskan ke fungsi yang sesuai dari apa pun yang beroperasi pada ( Wrapperberoperasi Client, dan Clientberoperasi pada koneksi HTTP). Saya mulai merasa tidak nyaman dengan ini, karena saya merasa saya sedang menguji implementasi kelas-kelas ini, bukan antarmuka. Secara teori, saya bisa mengubah kelas untuk memiliki implementasi lain yang benar-benar valid, tetapi pengujian saya akan gagal karena fungsi yang saya harapkan tidak dipanggil. Itu terdengar seperti tes rapuh bagi saya.

Setelah ini, saya berpikir tentang antarmuka kelas. Tes harus memverifikasi bahwa kelas benar-benar melakukan pekerjaan yang seharusnya mereka lakukan, bukan bagaimana mereka melakukannya. Jadi bagaimana saya bisa melakukan ini? Hal pertama yang terlintas dalam pikiran adalah mematikan permintaan API eksternal. Namun, saya gugup menyederhanakan layanan eksternal. Banyak contoh API yang terhapus yang saya lihat baru saja memberikan tanggapan kalengan, yang terdengar seperti cara yang sangat mudah untuk hanya menguji bahwa kode Anda berjalan dengan benar terhadap API palsu Anda. Alternatifnya adalah mengolok-olok layanan, yang tidak mungkin dilakukan, dan harus selalu diperbarui setiap kali layanan nyata berubah - yang terasa seperti kerja keras dan buang-buang waktu.

Akhirnya, saya membaca ini dari jawaban lain pada programmer SE :

Tugas klien API jarak jauh adalah mengeluarkan panggilan tertentu - tidak lebih, tidak kurang. Oleh karena itu, pengujiannya harus memverifikasi bahwa ia mengeluarkan panggilan-panggilan itu - tidak lebih, tidak kurang.

Dan sekarang saya kurang lebih yakin - saat menguji Client, yang saya perlu uji adalah membuat permintaan yang benar ke API (Tentu saja, selalu ada kemungkinan bahwa API akan berubah tetapi pengujian saya terus berjalan - tapi itu di mana tes integrasi akan berguna). Karena Clienthanya pemetaan 1: 1 dengan API, kekhawatiran saya sebelumnya tentang perubahan dari satu implementasi yang valid ke yang lain tidak benar-benar berlaku - hanya ada satu implementasi yang valid untuk setiap metode Client.

Namun, saya masih terjebak dengan Wrapperkelas. Saya melihat opsi berikut:

  1. Saya mematikan Clientkelas dan hanya menguji bahwa metode yang sesuai dipanggil. Dengan cara ini, saya melakukan hal yang sama seperti di atas tetapi memperlakukannya Clientsebagai stand-in untuk API. Ini menempatkan saya kembali ke tempat saya mulai. Sekali lagi, ini memberi saya perasaan tidak nyaman implementasi pengujian, bukan antarmuka. Itu Wrapperbisa sangat baik diimplementasikan menggunakan klien yang sama sekali berbeda.

  2. Saya membuat mock Client. Sekarang saya harus memutuskan seberapa jauh harus pergi dengan mengejeknya - membuat tiruan lengkap dari layanan akan membutuhkan banyak usaha (lebih banyak pekerjaan daripada yang telah pergi ke perpustakaan itu sendiri). API itu sendiri sederhana, tetapi layanannya cukup kompleks (pada dasarnya datastore dengan operasi pada data itu). Dan lagi, saya harus menjaga tiruan saya tetap sinkron dengan yang asli Client.

  3. Saya hanya menguji bahwa permintaan HTTP yang sesuai sedang dibuat. Ini berarti bahwa Wrapperakan memanggil melalui Clientobjek nyata untuk membuat permintaan HTTP itu, jadi saya tidak benar-benar mengujinya secara terpisah. Ini membuatnya menjadi semacam unit test yang mengerikan.

Jadi saya tidak terlalu senang dengan solusi ini. Apa yang akan kamu lakukan? Apakah ada cara yang tepat untuk melakukan ini?

Joseph Mansfield
sumber
Saya cenderung menghindari pengujian unit dalam skenario ini di mana ada perpustakaan pihak ketiga melakukan sebagian besar pekerjaan kasar dan saya hanya memiliki pembungkus (terutama karena saya tidak tahu bagaimana melakukan ini dengan cara yang menguji segala sesuatu yang benar-benar bermakna). Secara umum saya melakukan pengujian integrasi dalam kasus-kasus itu, mungkin dengan layanan tiruan. Mungkin seseorang tahu cara membuat unit test yang sangat berarti untuk ini - saya cenderung memprioritaskan komponen paling penting dalam sistem di bawah kendali kami. Di sini bagian yang kritis berada di luar kendali kami. :-(

Jawaban:

10

TLDR : Meskipun mengalami kesulitan, Anda harus mematikan layanan dan menggunakannya untuk pengujian unit klien.


Saya tidak yakin bahwa "tugas klien API jarak jauh adalah mengeluarkan panggilan tertentu, tidak lebih, tidak kurang ...", kecuali jika API hanya terdiri dari titik akhir yang selalu mengembalikan status tetap, dan tidak mengkonsumsi atau menghasilkan data apa pun. Ini bukan API yang paling berguna ...

Anda juga ingin memeriksa bahwa klien tidak hanya mengirimkan permintaan yang benar, tetapi juga menangani konten tanggapan, kesalahan, pengalihan, dan lain-lain. Dan uji untuk semua kasus ini.

Seperti yang Anda perhatikan, Anda harus memiliki tes integrasi yang mencakup tumpukan penuh dari pembungkus -> klien -> layanan -> DB dan seterusnya, tetapi untuk menjawab pertanyaan utama Anda, kecuali jika Anda memiliki lingkungan di mana tes integrasi dapat dijalankan sebagai bagian dari setiap Membangun CI tanpa banyak sakit kepala (database uji bersama, dll.), Anda harus menginvestasikan waktu dalam membuat rintisan API.

Stub akan membiarkan Anda membuat implementasi layanan yang berfungsi, tetapi tanpa harus menerapkan lapisan apa pun di bawah layanan itu sendiri.

Anda dapat mempertimbangkan menggunakan solusi berbasis DI untuk mencapai hal ini, dengan implementasi pola Repositori di bawah sumber daya REST:

  • Ganti semua kode fungsional dalam penangan REST dengan panggilan ke IWhthingRepository.
  • Buat ProductionWh whateverRepository dengan kode yang diekstrak dari sumber daya REST, dan TestWh whateverRespository yang mengembalikan respons kalengan untuk digunakan selama pengujian unit.
  • Gunakan wadah DI untuk menyuntikkan DLL / kelas ProductionWh whateverRepository atau TestWh whateverRepository, dll. Tergantung pada konfigurasi.

Pokoknya, kecuali jika stubbing dan / atau refactoring layanan keluar dari pertanyaan baik secara politis atau praktis, saya mungkin akan melakukan sesuatu yang mirip dengan di atas. Jika tidak memungkinkan, maka saya akan memastikan untuk memiliki cakupan integrasi yang sangat baik dan menjalankannya sesering mungkin dengan pengaturan pengujian yang tersedia.

HTH

Dan1701
sumber