Saya telah berputar-putar mencoba mencari cara terbaik untuk menguji unit perpustakaan klien API yang saya kembangkan. Perpustakaan memiliki Client
kelas yang pada dasarnya memiliki pemetaan 1: 1 dengan API, dan Wrapper
kelas tambahan yang menyediakan antarmuka yang lebih ramah pengguna dari atas Client
.
Wrapper --> Client --> External API
Saya pertama kali menulis banyak pengujian terhadap keduanya Client
dan Wrapper
, secara efektif hanya menguji bahwa mereka meneruskan ke fungsi yang sesuai dari apa pun yang beroperasi pada ( Wrapper
beroperasi Client
, dan Client
beroperasi 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 Client
hanya 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 Wrapper
kelas. Saya melihat opsi berikut:
Saya mematikan
Client
kelas dan hanya menguji bahwa metode yang sesuai dipanggil. Dengan cara ini, saya melakukan hal yang sama seperti di atas tetapi memperlakukannyaClient
sebagai stand-in untuk API. Ini menempatkan saya kembali ke tempat saya mulai. Sekali lagi, ini memberi saya perasaan tidak nyaman implementasi pengujian, bukan antarmuka. ItuWrapper
bisa sangat baik diimplementasikan menggunakan klien yang sama sekali berbeda.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 asliClient
.Saya hanya menguji bahwa permintaan HTTP yang sesuai sedang dibuat. Ini berarti bahwa
Wrapper
akan memanggil melaluiClient
objek 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?
Jawaban:
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:
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
sumber