Otomatisasi pengujian layanan berbayar di iOS

Bagi mereka yang tertarik dengan topik otomatisasi di iOS, saya punya dua berita - baik dan buruk. Bagus: dalam aplikasi iOS untuk layanan berbayar, hanya satu titik integrasi yang digunakan - pembelian dalam aplikasi (pembelian internal dalam aplikasi ). Buruk: Apple tidak menyediakan alat apa pun untuk mengotomatiskan pembelian pengujian.

Pada artikel ini, saya sarankan Anda dan saya mencari metode otomatisasi universal yang melampaui kebaikan dan kejahatan Apple. Artikel ini akan berguna bagi siapa saja yang mengintegrasikan layanan pihak ketiga yang merupakan kotak hitam ke dalam aplikasi mereka: iklan, streaming, manajemen lokasi, dll. Biasanya, integrasi seperti itu sangat sulit untuk diuji, karena tidak ada cara untuk secara fleksibel mengkonfigurasi layanan pihak ketiga untuk menguji aplikasi.



Nama saya Victor Koronevich, saya Senior Test Automation Engineer di Badoo. Terlibat dalam otomatisasi seluler selama lebih dari sepuluh tahun. Bersama dengan kolega saya Vladimir Solodov, kami membuat laporan ini di konferensi Heisenbug. Dia juga membantu saya mempersiapkan teks ini.

Pada artikel sebelumnya , kami menjelaskan metode apa yang digunakan Badoo untuk menguji integrasi dengan penyedia pembayaran, yang kami miliki lebih dari 70. Dalam artikel ini kami akan berbicara lebih banyak tentang bagaimana kami berhasil mencapai otomatisasi yang stabil dan murah untuk menguji layanan berbayar dalam aplikasi iOS.

Mari kita mulai dengan gambaran umum penelitian kami:

  1. Definisi masalah
  2. Pernyataan masalah
  3. Solusi No. 1. Apple Sandbox
  4. Keputusan nomor 2. Fungsi Metode Mock dan Menggunakan Objek Palsu
  5. Penilaian keputusan: risiko utama
  6. Hasil
  7. Kesimpulan

Definisi masalah


Otomasi perlu dilakukan ketika kebutuhan alami muncul. Kapan saat ini datang bersama kami?

Ada banyak fitur gratis di aplikasi Badoo, tetapi yang berbayar memberi pengguna lebih banyak opsi. Mereka mendapatkannya dalam dua cara: untuk pinjaman - mata uang internal Badoo - atau dengan membeli langganan premium. Untuk sejumlah kredit tertentu, Anda dapat meningkatkan profil Anda di hasil pencarian ke tempat pertama, membuat hadiah kepada pengguna lain, dan banyak lagi. Langganan premium berlaku untuk jangka waktu tertentu dan memberikan beberapa opsi sekaligus: nyalakan mode tembus pandang, lihat orang-orang yang telah menunjukkan simpati kepada Anda, membatalkan hasil pemilihan Anda, dan lainnya.

Fitur-fitur ini muncul di Badoo secara bertahap. Dan beberapa tahun yang lalu, kami menguji layanan berbayar di aplikasi iOS hanya secara manual. Tetapi ketika fitur dan layar baru muncul, pengujian manual semakin lama semakin memakan waktu. Persyaratan untuk perubahan dalam aplikasi berasal dari sisi yang berbeda: dari pengembang sisi klien, pengembang sisi server dan bahkan penyedia Apple sendiri. Untuk satu tester, satu iterasi pengujian mulai memakan waktu sekitar delapan jam. Menjadi tidak mungkin untuk mendapatkan umpan balik cepat untuk pengembang di cabang mereka dalam waktu 30 menit, yang akhirnya dapat berdampak negatif terhadap daya saing produk.

Kami ingin mendapatkan hasil tes secepat mungkin. Dan mereka mengalami masalah: bagaimana mengatur pengujian regresi layanan berbayar di aplikasi iOS kami dengan biaya murah untuk mendapatkan hasil yang cepat dan stabil?

Pernyataan masalah


Jadi, dengan mempertimbangkan secara spesifik proses pengiriman produk akhir dan ukuran tim kami, kami ingin:

  • Uji setiap pembelian dalam aplikasi klien (pembayaran dan langganan satu kali);

  • ulangi pengujian berulang 10-20 kali sehari;
  • Dapatkan hasil pengujian ~ 150 skrip pengujian dalam waktu kurang dari setengah jam;
  • singkirkan kebisingan;
  • dapat menjalankan tes pada cabang tertentu dari kode pengembang, terlepas dari hasil menjalankan lainnya.

Sekarang kita telah merumuskan tugas, sekarang saatnya untuk memulai perjalanan ke dunia insinyur yang luar biasa dan solusinya.

Solusi No. 1. Apple Sandbox


Pertama-tama, kami mulai mencari informasi tentang mengatur pengujian otomatis layanan berbayar dalam dokumentasi Apple. Dan mereka tidak menemukan apa pun. Dukungan otomasi terlihat sangat sedikit. Jika sesuatu muncul, maka pengaturan otomasi dengan alat yang diusulkan sulit (mari kita ingat setidaknya UIAutomation , serta waktu ketika utilitas xcrun simctl pertama untuk iOS Simulator muncul) dan Anda harus mencari solusi rekayasa, termasuk di segmen open-source.

Dalam dokumentasi Apple untuk menguji layanan berbayar, Anda hanya dapat menemukan Apple Sandbox . Tidak jelas bagaimana mengikat kotak pasir ini dengan otomatisasi, tetapi kami memutuskan untuk meneliti solusi ini dengan serius. Fakta bahwa kotak pasir Android stabil memberi kami kepercayaan diri, dan pada saat itu kami sudah berhasil menulis tes di Android. Mungkin kotak pasir Apple akan sama baiknya?

Tetapi ketika kami menerapkan autotest menggunakan kotak pasir ini, kami minum sepenuhnya. Mari kita cepat membahas masalah utama.

1. Kelompok pengguna uji


Keterbatasan utama untuk otomatisasi telah menjadi fitur konten di kumpulan pengguna uji, yang harus memastikan kemandirian peluncuran autotests.

Untuk menjalankan hanya satu pembelian-otomatis dari pembelian berlangganan, kita perlu:

  1. ambil pengguna baru untuk otorisasi di kotak pasir;
  2. ubah pada simulator ID Apple tertaut saat ini;
  3. Masuk ke Badoo dengan Badoo
  4. sampai ke layar pembelian berlangganan dan pilih produk;
  5. Konfirmasikan pembelian dan masuk melalui ID Apple;
  6. pastikan pembelian berhasil;
  7. kirim pengguna Badoo untuk dibersihkan;
  8. hapus pengguna kotak pasir dari langganan.

Jika Anda mencoba untuk segera menggunakan pengguna yang sama dalam pengujian berikutnya, maka tidak mungkin untuk membeli langganan kedua. Anda harus menunggu hingga langganan pertama "memburuk", atau berhenti berlangganan di pengaturan. Seperti yang kami katakan di artikel pertama, kotak pasir memiliki masa berlaku berlangganan tertentu. Jika Anda membeli langganan "selama sebulan", maka Anda harus menunggu lima menit untuk menutupnya secara otomatis. Proses berhenti berlangganan itu sendiri juga tidak cepat.

Karenanya, untuk menjalankan pengujian baru yang sama, kita harus menunggu hingga langganan berakhir, atau mengambil pengguna "bersih" lainnya. Jika kita ingin menjalankan dua tes secara bersamaan secara independen satu sama lain, maka kita perlu memiliki setidaknya dua pengguna kotak pasir di kolam. Jadi, untuk menjalankan 100 tes otomatis secara paralel dalam 100 utas, kita membutuhkan 100 pengguna yang berbeda.

Dan sekarang mari kita bayangkan bahwa kita melakukan uji diri pada dua agen, yang masing-masing dapat menjalankannya dalam 100 utas. Dalam hal ini, kami membutuhkan setidaknya 200 pengguna!

2. Pemberitahuan "Buruk"


Nah, apa yang tidak bercanda! Kami mengorganisasikan kumpulan pengguna dan mulai menonton bagaimana tes berjalan. Mereka jatuh di sepanjang jalan, tetapi mayoritas - untuk alasan baru yang tidak kita ketahui. Kami mulai memahami dan menyadari bahwa ketika mengotorisasi, mengonfirmasi pembelian, dan bekerja sebagai pengguna di kotak pasir, App Store mengirimkan peringatan: misalnya, meminta nama pengguna dan kata sandi baru, mengkonfirmasi otorisasi dengan mengklik tombol "OK", memberikan informasi tentang kesalahan internal dengan tombol "OK" . Terkadang mereka muncul, kadang tidak. Dan jika mereka muncul, maka selalu dalam urutan yang berbeda.



Bagaimana mungkin kesalahan yang mencurigakan diabaikan begitu saja dalam autotest? Dan jika kesalahan nyata tiba, lalu apa yang harus saya lakukan? Area ini secara otomatis menjadi "zona buta" bagi kami, dan kami harus menulis penangan khusus untuk semua peringatan yang mungkin datang dari App Store.

Semua ini membuat tes lebih lambat:

  • peringatan dapat sampai pada langkah-langkah berbeda dari skenario pengujian, menghancurkan gagasan utama pengujian - Skenario Tes yang Dapat Diprediksi; kami harus menambahkan penangan kesalahan yang mengharapkan serangkaian peringatan yang diketahui yang mungkin muncul akan muncul;
  • terkadang variasi baru lansiran tiba atau kesalahan lainnya terjadi, jadi kami harus memulai kembali pengujian yang jatuh; ini meningkatkan waktu berjalan semua tes.

3. Apakah ada tes?


Jadi, pengguna di kolam diblokir, lalu dibersihkan selama n menit. Kami menjalankan pengujian dalam 120 utas, dan sudah ada cukup banyak pengguna di kumpulan ini, tetapi ini tidak cukup. Kami membuat sistem manajemen pengguna kami, membuat penangan yang waspada - dan kemudian hal itu terjadi. Kotak pasir telah menjadi tidak tersedia selama beberapa hari untuk setiap pengguna tes.

Tidak ada yang mengharapkan ini. Dan ini adalah jerami terakhir di piala kesabaran kami, yang akhirnya membunuh cinta kotak pasir Apple dan membuat kami memulai jalan di luar yang baik dan yang jahat. Kami menyadari bahwa kami tidak memerlukan otomatisasi semacam itu dan kami tidak ingin menderita lagi dengan keputusan berbahaya ini.

Keputusan nomor 2. Fungsi Metode Mock dan Menggunakan Objek Palsu


Jadi, kami minum masalah dengan otomatisasi di kotak pasir Apple. Tapi jangan berpikir bahwa di dunia seluler semuanya benar-benar buruk. Di Android, kotak pasir jauh lebih stabil - Anda dapat menjalankan autotest di sana.

Mari kita coba cari solusi lain untuk iOS. Tapi bagaimana cara melihatnya? Di mana mencarinya? Mari kita lihat sejarah pengujian dan pengembangan perangkat lunak: apa yang terjadi pada dunia gila Apple? Apa yang orang-orang yang telah menulis banyak buku dan memperoleh otoritas di dunia otomasi dan pengembangan perangkat lunak?

Saya segera teringat karya “Pola Tes Unit: Refactoring Test Code”, yang ditulis oleh Gerard Mesaroche ( ditinjau oleh Martin Fowler), - menurut pendapat saya, salah satu buku terbaik untuk penguji yang mengetahui setidaknya satu bahasa pemrograman tingkat tinggi dan ingin melakukan otomatisasi . Beberapa bab dari buku ini yang ditujukan untuk menguji SUT secara terpisah dari komponen lain aplikasi, yang merupakan "kotak hitam" kami, dapat membantu kami.

1. Pengantar moka dan palsu


Perlu dicatat bahwa dalam dunia pengujian otomatis tidak ada batas yang diterima secara umum antara konsep Tes Ganda, Test Stub, Test Spy, Mock Object, Obyek Palsu, Objek Dummy. Anda harus selalu mempertimbangkan terminologi penulis. Kita hanya membutuhkan dua konsep dari dunia besar Uji Ganda: fungsi tiruan dan objek palsu. Apa ini Dan mengapa kita membutuhkan ini? Kami memberikan definisi singkat tentang konsep-konsep ini sehingga kami tidak memiliki perbedaan pendapat.

Misalkan kita memiliki aplikasi dan komponen yang dibangun di dalamnya, yang bagi kita adalah "kotak hitam". Di dalam aplikasi, kita dapat memanggil fungsi dengan mengakses komponen ini dan mendapatkan hasil dari fungsi-fungsi ini. Bergantung pada hasilnya, aplikasi kita bereaksi dengan cara tertentu. Kadang-kadang hasil dari eksekusi fungsi dapat berupa keseluruhan entitas dengan sekelompok bidang yang mencerminkan data pengguna yang sebenarnya.

Pergantian fungsi untuk yang lain yang mengembalikan hasil yang diinginkan, sebut saja fungsi tiruan, atau cukup tiruan. Fungsi-fungsi ini mungkin memiliki tanda tangan yang sama, tetapi ini adalah dua fungsi yang berbeda.

Dan substitusi entitas yang diperoleh sebagai hasil dari fungsi untuk entitas palsu (berisi data yang diperlukan di bidang, dan kadang-kadang bahkan data yang rusak) akan disebut implementasi objek palsu. Anda dapat membaca lebih lanjut tentang ini dalam buku yang saya sebutkan di atas, atau dalam ringkasan lainnya untuk pengujian dan pengembangan perangkat lunak.

Untuk menyelesaikannya, mari kita tekankan beberapa fitur menggunakan fungsi tiruan dan objek palsu:

  1. Untuk membuat basah fungsinya, Anda perlu mengakses kode sumber dan tahu cara kerja aplikasi dengan komponen dari dalam di tingkat pengembang.
  2. Untuk mengimplementasikan objek palsu, Anda perlu mengetahui struktur objek nyata.
  3. Menggunakan fungsi tiruan memungkinkan konfigurasi aplikasi yang fleksibel dengan komponen.
  4. Menggunakan objek palsu memungkinkan Anda untuk memberikan entitas dengan properti apa pun.

Metode moki dan objek palsu sangat ideal untuk mengisolasi operasi komponen dalam aplikasi. Mari kita lihat bagaimana kita dapat menerapkan metode ini untuk menyelesaikan masalah kita, di mana App Store akan menjadi komponennya. Karena kekhasan menggunakan metode ini, pertama-tama kita harus beralih ke mempelajari sifat pekerjaan aplikasi kita dengan komponen, dan kemudian ke implementasi teknis untuk membuat mokeys dan benda palsu tertentu.

2. Bagaimana pembelian nyata terjadi


Sebelum kita mulai mendeskripsikan interaksi semua bagian sistem, mari kita sorot aktor utama:

  • pengguna aplikasi - aktor apa pun yang melakukan tindakan dengan aplikasi, itu bisa seseorang, atau mungkin ada skrip yang melakukan instruksi yang diperlukan;
  • aplikasi (dalam kasus kami, kami menggunakan aplikasi iOS Badoo yang diinstal di simulator iOS);
  • server - aktor yang memproses permintaan dari aplikasi dan mengirim kembali respons atau pemberitahuan asinkron tanpa permintaan klien (dalam hal ini, kami maksudkan satu server Badoo abstrak untuk menyederhanakan struktur);
  • App Store adalah aktor yang merupakan "kotak hitam" bagi kami: kami tidak tahu bagaimana pengaturannya di dalam, tetapi kami tahu antarmuka publiknya untuk memproses pembelian dalam aplikasi ( kerangka kerja StoreKit ), dan juga tahu cara memeriksa data di server Apple.

Mari kita lihat bagaimana pembelian terjadi. Seluruh proses dapat dilihat pada diagram:


Gambar 1. Skema pembayaran di App Store

Kami akan menjelaskan langkah demi langkah tindakan utama para aktor.

1. Titik awal adalah keadaan semua aktor sebelum membuka layar dengan daftar produk.

Apa layar ini dan bagaimana kita mendapatkannya?

Misalkan seorang pengguna menemukan orang yang menarik, membuka profilnya, menulis satu pesan dan ingin mengirim hadiah. Mengirim hadiah adalah layanan berbayar. Pengguna dapat menggulir profil ke bagian untuk mengirim hadiah atau langsung memilih hadiah dari obrolan.

Jika pengguna memilih hadiah dan tidak memiliki uang di akun, maka ia akan melihat daftar paket pinjaman yang berbeda (Wisaya Pembayaran) untuk pembelian. Titik awal dalam contoh kita adalah daftar hadiah. Dalam diagram, kita dapat mempertimbangkan titik seperti itu di layar apa pun sebelum menampilkan daftar produk untuk pembelian pinjaman atau berlangganan.

2. Membuka daftar produk.

Kami berada di titik awal, misalnya, pada daftar hadiah. Pengguna memilih salah satu hadiah dalam aplikasi. Aplikasi membuat permintaan ke server kami untuk mendapatkan daftar kemungkinan paket pinjaman ID Produk (100, 550, 2000, 5000). Server mengembalikan daftar ini ke aplikasi.

Selanjutnya, aplikasi mengirimkan daftar ID Produk yang diterima untuk verifikasi ke aktor App Store (kerangka kerja iOS sistem StoreKit yang masuk ke server Apple). Ini mengembalikan daftar produk yang terbukti - dan sebagai hasilnya, aplikasi menunjukkan kepada pengguna daftar akhir dari paket pinjaman dengan ikon dan harga.

3. Pemilihan produk dan pembuatan tanda terima.

Pengguna memilih produk berbayar. App Store memerlukan bukti pembelian dan otorisasi melalui Apple ID. Setelah otorisasi pengguna yang berhasil, kontrol ditransfer ke aplikasi. Aplikasi sedang menunggu tanda terima untuk dihasilkan di dalam paketnya sendiri. Pengguna saat ini melihat matahari, yang mengunci layar. Tanda terima itu dibuat dapat dipahami menggunakan metode appStoreReceiptURL dari kelas Bundle . Setelah cek dihasilkan oleh App Store, aplikasi memilih cek dari paketnya dan mengirimkan permintaan dengan cek dan data pengguna ke server Badoo.

4. Memeriksa cek di server Badoo.

Segera setelah server Badoo menerima cek dan data pengguna, itu mengirim mereka kembali ke sisi server Apple untuk melakukan siklus verifikasi pertama. Ini adalah salah satu rekomendasi dari Apple. Kemudian, dalam siklus verifikasi pertama ini, server menerima informasi tentang status langganan saat ini.

5. Mengirim pemberitahuan push (pemberitahuan push) dari server.

Server Badoo lagi memproses informasi yang diterima setelah verifikasi oleh Apple dan mengirimkan aplikasi tanggapan bersama dengan pemberitahuan push.

6. Pemberitahuan push dalam aplikasi.

Jika itu adalah pembelian pinjaman, maka segera saldo pengguna dalam aplikasi akan berubah dan dia akan melihat hadiah yang dikirim dalam obrolan. Jika ini adalah pembelian berlangganan, maka pengguna harus menunggu pemberitahuan push terakhir bahwa berlangganan diaktifkan.

3. Penentuan dependensi dan tes loop



Untuk diskusi lebih lanjut, kami memperkenalkan dua konsep lagi - ketergantungan eksternal dan rangkaian pengujian.

Ketergantungan eksternal


Yang kami maksud dengan dependensi eksternal adalah setiap interaksi dengan komponen, yang bagi kami merupakan "kotak hitam". Dalam hal ini, App Store bertindak sebagai komponen seperti itu dalam bentuk kerangka kerja sistem iOS (StoreKit), yang digunakan aplikasi iOS kami, dan server Apple, tempat permintaan verifikasi.

Mengelola dependensi ini dalam kondisi nyata tidak mungkin, aplikasi dipaksa untuk menanggapi sinyal output dari kotak hitam (lihat Gambar. 2).

Kami memiliki tiga dependensi eksternal:

  1. Memeriksa Produk StoreKit.
  2. Menerima dan mengganti tanda terima pembelian.
  3. Memeriksa cek di server Badoo.


Gambar 2. Ketergantungan eksternal

Sirkuit pengujian


Sirkuit pengujian - ini adalah bagian dari jalur yang akan kami lalui dan periksa selama proses pengujian.


Gambar 3. Test loop

Tujuan dari pekerjaan kami untuk menghilangkan dependensi adalah untuk membangun sirkuit pengujian yang sedekat mungkin dengan jalur nyata dan memungkinkan Anda untuk mengecualikan semua dependensi eksternal dan kontrol transfer ke sisi Anda.

Kami mempertimbangkan setiap ketergantungan secara berurutan.

4. Isolasi ketergantungan: implementasi teknis


Di perusahaan kami, untuk penerapan pembayaran, konsep PPP diambil, yang didasarkan pada antarmuka Penyedia Pembayaran. Ini adalah antarmuka utama untuk berinteraksi dengan aktor App Store (StoreKit) di dalam aplikasi kami, yang memiliki dua metode utama:

  1. mempersiapkan adalah metode yang bertanggung jawab untuk memeriksa produk;
  2. makePayment adalah metode yang memproses pembelian dalam aplikasi.

Semua pembayaran di iOS di-refactored sesuai dengan konsep ini, yang memungkinkan kami untuk mendapatkan Penyedia Pembayaran Mock kelas yang sederhana dan nyaman. Ini adalah antarmuka utama untuk berinteraksi dengan salinan nyaman perilaku StoreKit di dalam aplikasi kita. Apa artinya "copy nyaman"? Penyedia ini memiliki ejekan dari metode persiapan dan pembayaran yang melakukan apa yang kita inginkan. Mari kita lihat contoh potongan kode, bagaimana kita berhasil mengintegrasikan moki.

Ketergantungan No. 1. Memeriksa Produk StoreKit


Untuk memeriksa daftar produk, gunakan fungsi persiapan, yang mengembalikan daftar produk yang diperiksa. Kita dapat menggunakan tiruan di mana kita mematikan cek dan mengembalikan daftar produk yang masuk sebagai diverifikasi sepenuhnya. Dengan demikian, ketergantungan akan dihilangkan.


Gambar 4. Skema eliminasi ketergantungan pertama

Di bagian paling atas arsitektur dalam aplikasi kita adalah Penyedia Pembayaran. Ini mencerminkan antarmuka penyedia yang mungkin dalam aplikasi. Kode untuk mengimplementasikan mok dapat ditemukan di kelas Penyedia Pembayaran Mock.

public class MockPaymentProvider: PaymentProvider { public static var receipt: String? public static var storeKitTransactionID: String? public func prepare(products: [BMProduct]) -> [BMProduct] { return products } ... } 

Daftar 1. Mock client check

Di Penyedia Pembayaran Mock, kita bisa melihat penerapan metode persiapan. Keajaiban moka sangat sederhana: metode ini melewatkan memeriksa produk di sisi StoreKit, dan itu hanya mengembalikan daftar produk yang masuk. Implementasi persiapan yang sebenarnya terlihat seperti ini:

 public func prepare(products: [BMProduct]) -> [BMProduct] { let validatedProducts = self.productsSource.validate(products: products) return validatedProducts } 

Listing 2. Penyedia Pembayaran Toko Nyata

Ketergantungan No. 2. Menerima dan mengganti tanda terima pembelian


Ketergantungan kedua sedikit lebih rumit: kita harus menghapus otorisasi terlebih dahulu agar tidak menjaga kumpulan akun pengguna, dan kemudian entah bagaimana mendapatkan cek itu sendiri. Kami cukup menghapus formulir otorisasi:


Gambar 5. Menghapus formulir otorisasi saat melakukan pembayaran

Tidak sesederhana itu dengan cek. Ada banyak pertanyaan:

  1. Bagaimana cara mendapatkan tanda terima untuk produk yang tepat sebelumnya?
  2. Jika kami menerima cek, lalu kapan dan bagaimana cara memasangnya di dalam aplikasi?

Di sini aktor "Pengguna" memiliki peran baru - QA. Ketika kami menjalankan tes, kami tidak hanya dapat mengklik tombol pada antarmuka, tetapi juga memanggil metode API dari kerangka uji (metode yang mensimulasikan tindakan pengguna) dan layanan REST API (metode yang dapat melakukan keajaiban dari layanan Badoo internal). Kami di Badoo menggunakan alat QA API yang sangat kuat (Anda dapat menemukan semua kemampuannya di tautan: https://vimeo.com/116931200 ). Dialah yang membantu kami dalam pengujian dan memberikan cek untuk produk yang tepat di sisi server Badoo. Server Badoo adalah tempat terbaik untuk menghasilkan cek: ada enkripsi dan dekripsi cek, sehingga server tahu segalanya tentang struktur data ini.

Setelah kami menerima cek palsu, kami bisa memasukkannya melalui pintu belakang di sisi aplikasi. Selanjutnya, aplikasi akan mengirimkan cek palsu bersama dengan data pengguna ke server kami.


Gambar 6. Skema untuk penerimaan

Bagaimana ini menjadi mungkin secara teknis?

1. Untuk menyiapkan cek palsu di aplikasi, kami dapat menggunakan backdoor yang menyimpan cek palsu di bidang tanda terima MockPaymentProvider:

 #if BUILD_FOR_AUTOMATION @objc extension BadooAppDelegate { @objc func setMockPurchaseReceipt(_ receipt: String?) { PaymentProvidersFactory.useMockPaymentProviderForITunesPayments = true MockPaymentProvider.receipt = receipt } ... } #endif 

Daftar 3. Backdoor cek palsu

2. Aplikasi ini dapat menerima cek kami berkat MockPaymentProvider, di mana kami menggunakan tiruan makePayment dan cek tersimpan di MockPaymentProvider.receipt:

 public class MockPaymentProvider: PaymentProvider { ... public func makePayment(_ transaction: BPDPaymentTransactionContext) { ... if let receiptData = MockPaymentProvider.receipt?.data(using: .utf8) { let request = BPDPurchaseReceiptRequest(...) self.networkService.send(request, completion: { [weak self] (_) in guard let sSelf = self else { return } if let receipt = request.responsePayload() { sSelf.delegate?.paymentProvider(sSelf, didReceiveReceipt: receipt) } }) } else { self.delegate?.paymentProvider(self, didFailTransaction: transaction) } } } 

Listing 4. Memanggil moka pemrosesan pembelian dengan cek palsu

3. Mendapatkan cek palsu

Untuk mendapatkan cek palsu, kami menggunakan metode di server (lihat Listing 5). Dibutuhkan array default dengan data untuk menghasilkan data pemeriksaan dan menambahkan data yang diperlukan untuk produk tertentu.

 $new_receipt_model = array_replace_recursive( //       $this->getDefaultModel(), //       //,      $this->enrichModelUsingSubscription($nr), //        $this->enrichModelUsingInput($input) ); //  $new_receipt = $this->signReceipt( json_encode($new_receipt_model, true), $new_receipt_model ); 

Listing 5. Server bagian dari pembuatan cek

Untuk mengulangi struktur cek yang sebenarnya, pemeriksaan kustom yang dikirim oleh aplikasi harus dienkripsi menggunakan sertifikat. Kami menggunakan sertifikat kerja kami alih-alih sertifikat Apple.

 function signReceipt($receipt, $response)  { //     base64 $receipt = 'Subject: ' . base64_encode(json_encode($response)) . PHP_EOL . PHP_EOL . $receipt; file_put_contents($receipt_file, $receipt); ... //    $sign_result = openssl_pkcs7_sign( $receipt_file, $signed_receipt_file, 'file://'.$path_cert, 'file://'.$path_key, [], PKCS7_BINARY); ... //  $signed_content_with_headers = file_get_contents($signed_receipt_file); list($headers, $signed_content) = explode(PHP_EOL . PHP_EOL, $signed_content_with_headers); //  return str_replace(["\r\n", "\r", "\n"], '', $signed_content); } 

Listing 6. Metode untuk menandatangani cek dengan sertifikat

4. Hasilnya, dalam ujian kita mendapatkan:

 (/       "((\d+) |  (\d+) ?/) do |service_type| #    service_details = parse_options(service_type) #  QA API (  Badoo) receipt = QaApi::Billing.order_get_app_store_receipt(service_details) #   Backdoors.set_fake_receipt(receipt) end 

Daftar 7. Langkah uji Gherkin untuk kerangka Mentimun

Ketergantungan No. 3. Memeriksa cek di server Badoo


Untuk menghapus ketergantungan ketiga, Anda harus menyingkirkan verifikasi cek di server. Penting untuk diingat bahwa verifikasi dilakukan dalam dua tahap. Pada tahap pertama, cek diautentikasi berdasarkan tanda tangan dan sertifikat. Pada detik - cek dikirim ke App Store. Jika validasi berhasil pada tahap ini, kami akan menerima cek yang didekripsi yang dapat diproses.


Gambar 7. Menghapus verifikasi server

Pertama, server melakukan verifikasi awal dari pemeriksaan dalam metode verifikasiReceiptByCert dari kelas induk. Ini memverifikasi tanda tangan dengan sertifikat App Store. Dalam hal pemeriksaan palsu, verifikasi ini akan gagal karena ditandatangani oleh sertifikat kami, dan kami akan memanggil metode untuk verifikasi dengan verifikasi sertifikat lokalReceiptByLocalCert. Dalam metode ini, kami akan mencoba mendekripsi cek menggunakan sertifikat lokal, dan jika berhasil, kami akan menempatkan hasil dekripsi di bidang internal local_receipt kelas anak (metode addLocallyVerifiedReceipt).

 class EngineTest extends Engine function verifyReceiptByCert($receipt)  { $result = parent::verifyReceiptByCert($receipt); if ($result === -1 || empty($result)) { $result = $this->verifyReceiptByLocalCert($receipt); } return $result; } function verifyReceiptByLocalCert($receipt) { $receipt_file = tempnam(sys_get_temp_dir(), 'rcp'); file_put_contents($receipt_file, base64_decode($receipt)); $result = openssl_pkcs7_verify($receipt_file, PKCS7_BINARY, '/dev/null', [$DIR]); if ($result) { $this->addLocallyVerifiedReceipt($receipt, base64_decode($response)); } unlink($receipt_file); return $result; } class Engine function verifyReceiptByCert($receipt) { $receipt_file = tempnam(sys_get_temp_dir(), 'rcp'); file_put_contents($receipt_file, base64_decode($receipt)); $result = openssl_pkcs7_verify($receipt_file, PKCS7_BINARY, '/dev/null', [$DIR]); unlink($receipt_file); return $result; } 

Daftar 8. Verifikasi awal

Selama verifikasi sekunder (verifikasiReceipt), kami mendapatkan nilai bidang local_receipt dari kelas anak getLocallyVerifiedReceipt. Jika tidak kosong, maka kami menggunakan nilainya sebagai hasil verifikasi.

Jika bidangnya kosong, maka kami memanggil verifikasi sekunder dari kelas induk ( parent :: verifikasiReceipt). Di sana kami membuat permintaan ke App Store untuk verifikasi di sisinya. Hasil verifikasi dalam kedua kasus adalah cek yang didekripsi.

 class EngineTest extends Engine function verifyReceipt($receipt_encoded, $shared_secret, $env) { $response = $this->getLocallyVerifiedReceipt($receipt_encoded); if (!empty($response)) { return json_decode($response, true); } return parent::verifyReceipt($receipt_encoded, $shared_secret, $env); } class Engine function verifyReceipt($receipt_encoded, $shared_secret, $env) { $response = $this->_sendRequest($receipt_encoded, $shared_secret, $env); return $response; } 

Listing 9. Verifikasi sekunder

5. Uji coba video: beli pinjaman dan langganan


Tes nomor 1. Pembelian Berlangganan


Kapan
Saya masuk ke aplikasi sebagai pengguna baru dengan foto
Dan
Saya menghasilkan cek penagihan berlangganan satu bulan yang baru
Dan
Saya pergi ke profil saya
Lalu
Saya memastikan langganan dinonaktifkan
Kapan
Saya membuka daftar produk
Dan
Saya membeli paket berlangganan satu bulan
Lalu
Saya memeriksa notifikasi pembelian yang berhasil
Dan
Saya memastikan langganan diaktifkan

Video uji coba:


Nomor tes 2. Membeli pinjaman dan mengirim hadiah


Kapan
Saya masuk ke aplikasi sebagai pengguna baru dengan foto
Dan
Saya menambahkan sepuluh kredit ke profil saya
Dan
Saya menghasilkan cek kredit baru untuk 550 kredit
Dan
Saya membuat Leela pengguna baru
Dan
Leela memilih Ya untukku
Dan
Saya pergi ke People Nearby dan membuka profil Leela
Dan
Saya memilih "Ya" untuk Leela
Lalu
Saya memeriksa halaman pertandingan
Kapan
Saya memilih untuk mengirim hadiah reguler
Lalu
Saya memeriksa layar pembayaran dengan daftar paket
Kapan
Saya memilih untuk membeli 550 kredit
Lalu
Saya memeriksa notifikasi pembelian yang berhasil
Dan
Saya memastikan Leela menerima hadiah obrolan


Video uji coba:



Penilaian keputusan: risiko utama


Menghapus ketergantungan eksternal membawa risiko tertentu.

1. Konfigurasi salah.

Karena verifikasi tidak ada di pihak kami, kami dapat mengonfigurasi produk kami secara tidak benar di pihak Apple. Untuk melindungi dari kesalahan, kami menulis tes unit sisi server terpisah, yang memeriksa bahwa semua produk yang kami mulai di sisi Apple cocok dengan produk yang kami miliki di konfigurasi kami.

2. Kasus perbatasan.

Misalnya, ketika pembayaran sepenuhnya selesai, pengguna menerima pemberitahuan bahwa ia telah menyelesaikan, tetapi aplikasi kami tidak dapat menemukan cek yang harus dipalsukan sebagai akibat dari melakukan pembayaran ini. Risikonya terletak pada kenyataan bahwa kita sendiri melampirkan cek dengan bantuan pintu belakang, dan kita secara alami tidak dapat melacak kasus seperti itu. Untuk mengkompensasi risiko ini, kami melakukan pemeriksaan end-to-end menggunakan kotak pasir atau pembayaran nyata setelah rilis.

3. Tidak adil palsu atau penipuan.

Setelah membaca artikel ini, Anda mungkin berpikir bahwa karena Badoo menggunakan cek palsu, Anda dapat melampirkan sesuatu yang palsu kepada kami dan menggunakan layanan ini secara gratis. Agar risiko ini tidak terwujud, kami menandatangani semuanya dengan sertifikat kami sendiri dan membatasi penggunaan moks dan cek palsu untuk tes fungsional yang hanya dijalankan di lingkungan pengembangan kami.

4. Ubah format cek.

Ini adalah risiko paling serius. Mengubah format pemeriksaan dimungkinkan ketika Apple mengubah sesuatu tanpa memperingatkan kami. Kami memiliki kasus seperti itu: ketika beralih ke iOS 11, format cek benar-benar berubah. Kami membuat cek palsu di server kami dan menggunakannya dalam pengujian. Semuanya sempurna dengan kami: semua bidang ada di tempatnya, semuanya indah, semuanya sedang diproses. Tetapi ketika kami beralih ke sistem nyata, tidak ada yang berhasil. Bidang yang signifikan pada cek tidak lagi ada.

Bagaimana cara mengkompensasi risiko ini? Pertama, kami tidak mengecualikan kemungkinan pengujian end-to-end dari kotak pasir sebelum rilis dan pembayaran riil setelah rilis. Sekarang kami berada dalam fase aktif proyek untuk memeriksa notifikasi, ketika kami mencoba untuk mengklasifikasikan semua cek yang kami terima dari produksi berdasarkan apakah kami memahami apa itu atau tidak mengerti. Jika jawabannya tidak, maka kami mulai memproses semuanya secara manual, melihat apa yang telah berubah, apa yang salah, apa yang perlu diubah dalam sistem kami.
Resiko
Alasan
Bagaimana cara memberi kompensasi
konfigurasi yang salah
hapus cek
unit test di server
kasus tepi
(periksa tidak terkirim)
gunakan backdoor
E2E-cek (kotak pasir dan pembayaran riil)
penipuan penipuan, penipuan
pemberitahuan dan periksa pembuatan di server
sertifikat sendiri
ubah format cek
pemberitahuan dan periksa pembuatan di server
verifikasi notifikasi nyata dan cek pada prod (proyek baru),
E2E-cek (kotak pasir dan pembayaran riil)

Hasil



Pertimbangkan keuntungan utama yang bisa kami dapatkan sebagai hasil dari penerapan metode moki dan objek palsu.

Otomatisasi layanan berbayar yang murah, cepat, dan stabil di iOS


Bersama dengan tim pengujian manual iOS (terima kasih khusus kepada Colin Chan), kami dapat menulis lebih dari 150 tes otomatis untuk pembayaran. Ini adalah jumlah pertanggungan yang cukup besar untuk satu area aplikasi.

Berkat paralelisasi, kami bisa mendapatkan hasilnya hanya dalam 15-20 menit pada cabang pengembang klien iOS atau pengembang server penagihan. Sebelum otomatisasi, pengujian manual pada area ini oleh satu orang membutuhkan waktu delapan jam.

Kami juga dapat menguji sebagian besar kasus uji dengan menyiapkan Penyedia Pembayaran Mock melalui moki seperti yang kami butuhkan. Dengan bantuan mooks, kami belajar cara mematikan pemeriksaan produk dan mensimulasikan kasus ketika pemeriksaan dilakukan sebagian. Dengan demikian, kami membuka kasus yang tidak dapat kami uji secara prinsip sebelumnya.

Regresi fungsional dalam pengembangan fitur baru


Otomasi bekerja sangat baik dalam kasus-kasus tersebut ketika pengembang dalam proses mengerjakan fitur baru memengaruhi fungsionalitas lama. Kami memiliki contoh ketika pengembang melakukan fitur kompleks dengan caching dan menjalankan pengujian otomatis kami. Beberapa dari mereka jatuh dalam kesalahan. Dia melihatnya dan memperbaikinya. Kemudian dia memulai lagi autotest - dan lagi, sesuatu jatuh. Akibatnya, ia melakukan serangkaian iterasi sampai saat ketika semuanya mulai bekerja secara normal di sisi aplikasi.

Regresi fungsional dalam refactoring pembayaran


Mungkin otomatisasi paling sukses dan efisien yang mungkin terjadi di bidang refactoring kode. Dalam hal ini, hanya perubahan implementasi internal - tidak perlu mengubah kode autotest. UI tidak berubah dengan cara apa pun, dan uji coba dapat didorong secara efisien.

Menguji fitur eksperimental dari Apple: masa tenggang


Sistem serupa sepenuhnya dapat dipertukarkan saat Anda menguji integrasi baru yang belum diimplementasikan di kotak pasir. Begitu juga dengan masa tenggang. Fungsi ini tidak ada di kotak pasir. Masa tenggang di Apple belum tersedia untuk semua orang. Ini adalah proyek percontohan yang diterapkan Badoo dengan Apple. Untuk memeriksa masa tenggang, kami perlu menambahkan sepotong kode JSON di sini:

 pending_renewal_info:[ { expiration_intent: 2 grace_period_expires_date: 2019-04-25 15:50:57 Etc/GMT auto_renew_product_id: badoo.productId original_transaction_id: 560000361869085 is_in_billing_retry_period: 1 grace_period_expires_date_pst: 2019-04-25 08:50:57 America/Los_Angeles product_id: badoo.productId grace_period_expires_date_ms: 1556207457000 auto_renew_status: 1 }] 

Listing 10. Masa tenggang untuk berlangganan

Kami melakukan ini dengan sangat mudah hanya dalam beberapa detik. Dalam sistem kami, kami dapat menguji reaksi kami terhadap fitur baru. Sekarang kami menjalankan fungsi ini pada prod.

Pengujian kualitas produk dalam metode komposisi


Sebagai hasil dari penelitian kami, kami dapat menggambarkan metode yang menghilangkan kebisingan dari ketergantungan eksternal. Ini membantu pengembang klien dalam proses mengembangkan fitur menemukan bug pada tahap awal.

Tetapi jangan berpikir bahwa kami dapat menguji semuanya dengan metode ini. Untuk menguji semuanya, lebih baik menggunakan komposisi metode: pengujian dengan kartu nyata pada produk, pengujian di kotak pasir, metode mokes dan benda palsu, unit dan pengujian integrasi. Harap ingat keseimbangan piramida pengujian dan jangan mencoba menyelesaikan semua masalah dengan satu metode. Hal ini dapat menyebabkan otomatisasi yang menyedihkan di kotak pasir, hingga pengujian manual yang menyedihkan dengan kartu nyata dari semua kasus dan banyak kesalahan serius lainnya di tempat di mana penampilan mereka adalah yang paling menyakitkan.

Kesimpulan


Sebagai hasil dari penelitian kami, kami mendapatkan metode pengujian yang murah, cepat dan stabil tidak hanya layanan berbayar di iOS, tetapi juga komponen apa pun yang tertanam dalam aplikasi sebagai "kotak hitam". Sekarang di Badoo kami menerapkan metode ini untuk pengujian pada penyedia berbayar Android (Global Charge, Boku, Centili) yang memiliki kotak pasir tidak stabil atau batasan lainnya. Kami juga menggunakan metode moki untuk menguji iklan, streaming, dan geolokasi.

Perlu dikatakan bahwa proses memperkenalkan metode baru tidak cepat. Saya harus bernegosiasi dengan empat tim: iOS QA, iOS Dev, Billing QA, Billing Dev. Tidak semua orang ingin beralih ke metode baru, takut risiko. Kadang-kadang itu adalah dogmatis: selama bertahun-tahun kami menguji di kotak pasir, dan kekuatan utama yang dapat menghancurkan dogma adalah keinginan para penguji penagihan dan platform iOS untuk mengubah situasi dan menyingkirkan siksaan. Kemudian, pengembang menyadari kelebihan metode ini sebagai diagnostik yang akurat (kami tidak dapat menemukan bug di kotak pasir, tetapi bug dari klien atau server kami), fleksibilitas dalam menyiapkan komponen (kami dapat dengan mudah menguji kasus negatif pada tingkat integrasi) dan, tentu saja, jawabannya adalah 30 menit di cabang dengan kode yang dikembangkan.

Banyak terima kasih kepada semua orang yang telah membaca sampai akhir. Terima kasih banyak kepada semua orang yang telah membantu dan berpartisipasi dalam proyek ini. Terima kasih khusus kepada orang-orang ini:

  • Peter Kolpashchikov adalah pengembang iOS yang membantu membuat moki di sisi klien dan mengembangkan konsep PPP;
  • Vladimir Solodov - QA Penagihan, yang membantu dengan QA API untuk menghasilkan cek palsu dan checkout dari server penagihan;
  • Maxim Filatov dan Vasily Stepanov - Tim Penagihan Billing, yang membantu dengan kode server penagihan;
  • iOS Dev Team - pengembang yang dapat memperbaiki pembayaran kami dalam konsep baru, memungkinkan penggunaan moka;
  • Tim QA iOS adalah tim pengujian yang luar biasa yang menulis banyak uji coba;
  • Billing Tim QA - penguji yang membantu meneliti masalah.

Source: https://habr.com/ru/post/id460667/


All Articles