Halo semuanya! Nama saya Pasha dan saya seorang insinyur QA untuk tim Pemrosesan Pesanan di Lamoda. Saya baru-baru ini berbicara di PHP Badoo Meetup. Hari ini saya ingin memberikan transkrip dari laporan saya.
Kami akan berbicara tentang Codeception, tentang bagaimana kami menggunakannya di Lamoda dan bagaimana menulis tes di atasnya.
Lamoda memiliki banyak layanan. Ada layanan klien yang berinteraksi langsung dengan pengguna kami, dengan pengguna situs, aplikasi seluler. Kami tidak akan membicarakannya. Dan ada yang oleh perusahaan kami disebut backend mendalam - ini adalah sistem back-office kami yang mengotomatiskan proses bisnis kami. Ini termasuk pengiriman, penyimpanan, otomasi studio foto dan call center. Sebagian besar layanan ini dikembangkan dalam PHP.
Berbicara singkat tentang tumpukan kami, ini adalah PHP + Symfony. Di sana-sini ada proyek lama di Zend'e. PostgreSQL dan MySQL digunakan sebagai basis data, dan Rabbit atau Kafka digunakan sebagai sistem pengiriman pesan.
Mengapa PHP backends?Karena mereka biasanya memiliki API bercabang - itu REST, di beberapa tempat ada sedikit SOAP. Jika mereka memiliki UI, maka UI ini lebih merupakan tambahan, yang digunakan pengguna internal kami.
Mengapa kita perlu autotests di Lamoda?Secara umum, ketika saya datang untuk bekerja di Lamoda, ada slogan seperti: "Mari kita singkirkan regresi manual". Kami tidak akan menguji regresi apa pun secara manual. Dan kami mengerjakan tugas ini. Sebenarnya, ini adalah salah satu alasan utama mengapa kita membutuhkan autotest - agar tidak mendorong regresi dengan tangan. Mengapa kita membutuhkan ini? Hak untuk rilis dengan cepat. Sehingga kami dapat dengan cepat, tanpa rasa sakit meluncurkan rilis kami dan pada saat yang sama memiliki semacam kisi-kisi dari tes mandiri yang akan mereka beri tahu, baik atau buruk. Ini mungkin tujuan yang paling penting. Tetapi ada beberapa pembantu, yang juga ingin saya sampaikan.
Mengapa kita perlu uji otomatis?
- Jangan menguji regresi dengan tangan Anda
- Rilis cepat
- Gunakan sebagai dokumentasi
- Mempercepat orientasi karyawan baru
- Autotests mudah digunakan (dalam beberapa kasus) sebagai dokumentasi. Terkadang lebih mudah untuk mengikuti tes, melihat kasus mana yang dicakup, cara kerjanya, dan memahami cara kerja fungsi ini atau itu, dan mempercepat masuknya karyawan baru - baik pengembang maupun penguji - ke dalam proyek baru. Ketika Anda duduk untuk menulis autotests, segera menjadi jelas bagaimana sistem bekerja.
Oke, bicarakan mengapa kita perlu autotest. Sekarang mari kita bicara tentang tes apa yang kita tulis di Lamoda.

Ini adalah piramida pengujian yang cukup standar, dari pengujian unit hingga pengujian E2E, di mana beberapa rantai bisnis sudah diuji. Saya tidak akan berbicara tentang dua tingkat yang lebih rendah, bukan karena mereka dicat dengan warna putih. Ini adalah tes pada kode itu sendiri, ditulis oleh pengembang kami. Dalam kasus ekstrim, tester dapat masuk ke Permintaan Tarik, melihat kode dan berkata: "Yah, ada sesuatu yang tidak cukup kasus di sini, mari kita bahas hal lain." Ini melengkapi pekerjaan penguji untuk tes ini.
Kami akan berbicara tentang level di atas, yang ditulis oleh pengembang dan penguji. Mari kita mulai dengan tes sistem. Ini adalah tes yang menguji API (REST atau SOAP), menguji beberapa logika sistem internal, berbagai perintah, antrian parse di Rabbit, atau pertukaran dengan sistem eksternal. Sebagai aturan, tes ini cukup atom. Mereka tidak memeriksa rantai apa pun, tetapi memeriksa satu tindakan. Misalnya, satu metode API atau satu perintah. Dan mereka memeriksa sebanyak mungkin kasus, baik positif maupun negatif.
Silakan, tes E2E. Saya membaginya menjadi 2 bagian. Kami memiliki tes yang menguji sekelompok UI dan backend. Dan ada tes yang kami sebut tes aliran. Mereka menguji rantai - kehidupan suatu objek dari awal hingga akhir.
Misalnya, kami memiliki sistem untuk mengelola pemrosesan pesanan kami. Di dalam sistem seperti itu dapat ada tes - perintah dari penciptaan ke pengiriman, yaitu, melewati semua status. Pada pengujian seperti itu maka sangat mudah dan sederhana untuk melihat bagaimana sistem bekerja. Anda segera melihat seluruh aliran objek tertentu, dengan sistem eksternal apa semua ini berinteraksi, perintah apa yang digunakan untuk ini.
Karena UI ini digunakan oleh pengguna internal, akses lintas-browser tidak penting bagi kami. Kami tidak menjalankan tes ini di peternakan apa pun, cukup bagi kami untuk memeriksa dalam satu browser, dan terkadang kami bahkan tidak perlu menggunakan browser.
"Mengapa kita memilih Codeception untuk otomatisasi pengujian?" - Anda mungkin bertanya.
Sejujurnya, saya tidak punya jawaban untuk pertanyaan ini. Ketika saya datang ke Lamoda, Codeception sudah dipilih sebagai standar untuk menulis autotests, dan saya menemukan sebenarnya. Tetapi setelah bekerja dengan kerangka kerja ini untuk beberapa waktu, saya masih mengerti mengapa Codeception. Ini yang ingin saya bagikan dengan Anda.
Mengapa codeception?- Anda dapat menulis dan menjalankan tes apa pun yang sama (unit, fungsional, penerimaan).
- Banyak rake telah diselesaikan, banyak modul telah ditulis.
- Di semua proyek, meskipun kebutuhan sedikit berbeda, tes akan terlihat sama.
- Konsep Codeception menyarankan Anda menulis tes apa pun pada kerangka kerja ini: unit, integrasi, fungsional, penerimaan. Dan Anda, setidaknya, mereka akan diluncurkan secara setara.
- Codeception adalah prosesor yang cukup kuat di mana banyak masalah, banyak pertanyaan, banyak tugas untuk tes telah diselesaikan. Jika sesuatu tidak diputuskan, kemungkinan besar Anda akan menemukan sesuatu dari luar - beberapa tambahan untuk beberapa pekerjaan tertentu. Anda tidak perlu menulis pembungkus uji apa pun untuk basis data, untuk hal lain. Hanya mengambil dan menghubungkan modul ke Codeception dan bekerja dengannya.
- Nah, nilai tambah seperti itu (mungkin itu lebih cocok untuk perusahaan besar ketika Anda memiliki banyak proyek dan layanan) - dalam semua proyek tes akan terlihat plus atau minus sama. Ini sangat keren.
Secara singkat saya akan mengatakan seperti apa Codeception, karena banyak yang bekerja dengannya.

Codeception bekerja pada model aktor. Setelah Anda menyeretnya ke dalam proyek dan menginisialisasi, struktur seperti itu dihasilkan.
Kami memiliki file yml, di sini di bawah ini -
functional.suite.yml ,
integrasi.suit.yml ,
unit.suite.yml . Mereka menciptakan konfigurasi tes Anda. Ada ayah untuk setiap jenis tes, di mana tes ini, ada 3 ayah tambahan:
_
data - untuk data uji;
_
output - di mana laporan ditempatkan (xml, html);
_
dukungan - di mana beberapa pembantu bantu, fungsi, dan semua yang Anda tulis digunakan untuk digunakan dalam pengujian Anda.
Untuk memulainya, saya akan memberi tahu Anda apa yang kami ambil dari Codeception dan menggunakannya di luar kotak, tidak mengubah apa pun, tidak menyelesaikan tugas atau masalah tambahan.
Modul standar- Phpbrowser
- SISA
- Db
- Cli
- AMQP
Modul tersebut adalah PhpBrowser. Modul ini adalah pembungkus lebih dari Guzzle yang memungkinkan Anda untuk berinteraksi dengan aplikasi Anda: membuka halaman, mengisi formulir, mengirimkan formulir. Dan jika Anda tidak peduli tentang cross-browser dan pengujian browser, jika Anda tiba-tiba menguji UI, Anda dapat menggunakan PhpBrowser. Sebagai aturan, kami menggunakannya dalam pengujian UI kami, karena kami tidak memerlukan logika interaksi yang rumit, kami hanya perlu membuka halaman dan melakukan sesuatu yang kecil di sana.
Modul kedua yang kami gunakan adalah REST. Saya pikir namanya memperjelas apa yang dia lakukan. Untuk setiap interaksi http, Anda dapat menggunakan modul ini. Sepertinya saya bahwa hampir semua interaksi diselesaikan di dalamnya: tajuk, cookie, otorisasi. Semua yang Anda butuhkan ada di dalamnya.
Modul ketiga yang kami gunakan di luar kotak adalah modul Db. Dalam versi terbaru Codeception, dukungan untuk tidak satu, tetapi beberapa database telah ditambahkan di sana. Oleh karena itu, jika Anda tiba-tiba memiliki beberapa database di proyek Anda, sekarang ini berfungsi dengan baik.
Modul Cli, yang memungkinkan Anda untuk menjalankan perintah
shell dan
bash dari pengujian, dan kami juga menggunakannya.
Ada modul AMQP yang berfungsi dengan pialang pesan apa pun yang didasarkan pada protokol ini. Saya ingin mencatat bahwa itu secara resmi diuji di RabbitMQ. Karena kami menggunakan RabbitMQ, semuanya baik-baik saja dengannya.
Bahkan, Codeception, setidaknya dalam kasus kami, mencakup 80-85% dari semua tugas yang kita butuhkan. Tetapi saya masih harus mengerjakan sesuatu.
Mari kita mulai dengan SABUN.

Dalam layanan kami, di beberapa tempat ada titik akhir SOAP. Mereka perlu diuji, ditarik, ada hubungannya dengan mereka. Tetapi Anda akan mengatakan bahwa dalam Codeception ada modul seperti itu yang memungkinkan Anda mengirim permintaan dan kemudian melakukan sesuatu dengan jawabannya. Entah bagaimana untuk menguraikan, tambahkan cek dan semuanya OK. Tetapi modul SOAP tidak bekerja di luar kotak dengan beberapa titik akhir SOAP.

Sebagai contoh, kami memiliki monolit yang memiliki beberapa WSDL, beberapa titik akhir SOAP. Ini berarti bahwa tidak mungkin dalam modul Codeception untuk mengkonfigurasi ini dalam file yml sehingga dapat berfungsi dengan beberapa.

Codeception memiliki konfigurasi ulang modul dinamis, dan Anda dapat menulis beberapa jenis adaptor Anda untuk menerima, misalnya, modul SOAP dan mengkonfigurasi ulang secara dinamis. Dalam hal ini, perlu untuk mengganti titik akhir dan skema yang digunakan. Kemudian dalam pengujian, jika Anda perlu mengubah titik akhir yang ingin Anda kirimi permintaan, kami mendapatkan adaptor kami dan mengubahnya ke titik akhir yang baru, ke sirkuit baru dan mengirimkan permintaan ke sana.

Dalam Codeception, tidak ada pekerjaan dengan Kafka dan tidak ada tambahan pihak ketiga yang kurang lebih resmi untuk bekerja dengan Kafka. Tidak ada yang perlu dikhawatirkan, kami menulis modul kami.

Jadi itu dikonfigurasi dalam file yml. Beberapa pengaturan ditetapkan untuk broker, untuk konsumen dan untuk topik. Pengaturan ini, ketika Anda menulis modul Anda, Anda kemudian dapat menariknya ke dalam modul dengan fungsi inisialisasi dan inisialisasi modul ini dengan pengaturan yang sama. Dan, pada kenyataannya, modul memiliki semua metode lain untuk diterapkan - letakkan pesan dalam topik dan bacalah. Hanya itu yang Anda butuhkan dari modul ini.
Kesimpulan : modul untuk Codeception mudah ditulis.
Silakan. Seperti yang saya katakan, Codeception memiliki modul Cli - pembungkus untuk perintah
shell dan bekerja dengan output mereka.

Tetapi kadang-kadang perintah
shell perlu dijalankan bukan dalam tes, tetapi dalam aplikasi. Secara umum, tes dan aplikasi adalah entitas yang sedikit berbeda, mereka dapat terletak di tempat yang berbeda. Tes dapat dijalankan di satu tempat, dan aplikasi mungkin di tempat lain.
Jadi mengapa kita perlu menjalankan
shell di tes?
Kami memiliki perintah dalam aplikasi yang, misalnya, mengurai antrian di RabbitMQ dan memindahkan objek berdasarkan status. Perintah-perintah ini dalam mode pro diluncurkan dari bawah supervisor. Pengawas memantau implementasinya. Jika mereka jatuh, maka dia mulai lagi dan seterusnya.
Saat kami uji, supervisor tidak berjalan. Jika tidak, tes menjadi tidak stabil, tidak dapat diprediksi. Kami sendiri ingin mengontrol peluncuran perintah ini di dalam aplikasi. Oleh karena itu, kita perlu menjalankan perintah ini dari pengujian di aplikasi. Kami menggunakan dua opsi. Yang satu itu, yang lain - pada prinsipnya, semuanya sama, dan semuanya berfungsi.
Bagaimana cara menjalankan
shell dalam suatu aplikasi?
Pertama: jalankan tes di tempat yang sama di mana aplikasi berada. Karena semua aplikasi yang kami miliki di Docker, pengujian dapat dijalankan dalam wadah yang sama di mana layanan itu sendiri berada.
Opsi kedua: buat wadah terpisah untuk pengujian, beberapa
pelari ujian , tetapi buatlah sama dengan aplikasi. Yaitu, dari gambar Docker yang sama, dan kemudian semuanya akan bekerja sama.

Masalah lain yang kami temui dalam pengujian adalah bekerja dengan berbagai sistem file. Di bawah ini adalah contoh dari apa yang dapat dan harus Anda kerjakan. Tiga yang pertama relevan bagi kita. Ini adalah Webdav, SFTP, dan sistem file Amazon.
Dengan apa Anda perlu bekerja?
- Webdav
- FTP / SFTP
- AWS S3
- Lokal
- Azure, Dropbox, google drive
Jika Anda mencari-cari melalui Codeception, Anda dapat menemukan beberapa modul untuk hampir semua sistem file yang kurang lebih populer.

Satu-satunya hal yang saya tidak temukan adalah untuk WebDAV. Tetapi sistem file ini, plus atau minus, sama dalam hal pekerjaan eksternal dengan mereka, dan kami ingin bekerja dengan mereka dengan cara yang sama.
Kami menulis modul kami yang disebut Flysystem. Itu terletak di
Github di domain publik dan mendukung 2 sistem file - SFTP dan Webdav - dan memungkinkan Anda untuk bekerja dengan keduanya menggunakan API yang sama.

Dapatkan daftar file, bersihkan direktori, tulis file, dan sebagainya. Jika Anda juga menambahkan sistem file Amazon di sana, kebutuhan kami pasti akan tercakup.
Poin berikutnya, saya pikir, sangat penting untuk autotest, terutama tingkat sistem, bekerja dengan basis data. Secara umum, saya ingin, seperti pada gambar, - VZHUH dan semuanya dimulai, berfungsi, dan database ini harus kurang didukung dalam tes.

Apa tugas utama yang saya lihat di sini:
- Cara menggelar basis data struktur yang diinginkan - Db
- Cara mengisi database dengan data uji - Db, Jadwal
- Cara membuat pilihan dan memeriksa - Db
Untuk semua 3 tugas dalam Codeception, ada 2 modul - Db, yang sudah saya bicarakan, yang lain disebut Fixtures.
Dari 2 modul dan 3 tugas ini, kami hanya menggunakan DB untuk tugas ketiga.
Untuk tugas pertama, Anda bisa menggunakan DB. Di sana Anda dapat mengkonfigurasi dump SQL dari mana database akan digunakan, baik, modul dengan perlengkapan, saya pikir jelas mengapa itu diperlukan.
Akan ada perlengkapan dalam bentuk array yang dapat disimpan ke dalam basis data.
Seperti yang saya katakan, 2 tugas pertama yang kami selesaikan sedikit berbeda, sekarang saya akan memberi tahu Anda bagaimana kami melakukannya.
Penempatan basis data- Meningkatkan wadah dengan PostgreSQL atau MySQL
- Kami menggulung semua migrasi dengan migrasi doktrin
Yang pertama adalah tentang menggunakan basis data. Bagaimana ini terjadi dalam tes. Kami menaikkan wadah dengan database yang diinginkan - baik PostgreSQL atau MySQL, lalu gulung semua migrasi yang diperlukan menggunakan
migrasi doktrin . Semuanya, database dari struktur yang diinginkan sudah siap, dapat digunakan dalam tes.
Mengapa kami tidak menggunakan peredam - karena itu tidak perlu didukung. Ini adalah semacam dump yang terletak pada tes, yang perlu terus diperbarui jika ada perubahan dalam database. Ada migrasi - tidak perlu mengelola dump.
Poin kedua adalah pembuatan data uji. Kami tidak menggunakan modul Fixtures dari Codeception, kami menggunakan bundel
Symfony untuk fixture.

Ada
tautan ke sana dan contoh bagaimana Anda bisa membuat fixture dalam database.
Fixture Anda kemudian akan dibuat sebagai beberapa objek domain, dapat disimpan dalam database, dan data uji akan siap.
Mengapa DoctrineFixtureBundle?
- Lebih mudah untuk membuat rantai benda terkait.
- Lebih sedikit duplikasi data jika perlengkapan untuk tes yang berbeda serupa.
- Lebih sedikit pengeditan saat mengubah struktur basis data.
- Kelas fixture jauh lebih visual daripada array.
Mengapa kita menggunakannya? Ya, untuk alasan yang sama - perlengkapan ini jauh lebih mudah dirawat daripada perlengkapan dari Codeception. Lebih mudah untuk membuat rantai benda terkait, karena semuanya ada dalam bundel symfony. Lebih sedikit data yang perlu digandakan, karena fixture dapat diwarisi, ini adalah kelas. Jika struktur database berubah, array ini selalu perlu diedit, dan kelas tidak selalu. Perlengkapan dalam bentuk objek domain selalu lebih terlihat daripada array.
Kami berbicara tentang database, mari kita bicara sedikit tentang moki.
Karena ini adalah tes dari tingkat yang cukup tinggi yang menguji seluruh sistem dan karena sistem kami sangat saling berhubungan, jelas bahwa ada beberapa pertukaran dan interaksi. Sekarang kita akan berbicara tentang mokeys tentang interaksi antar sistem.
Aturan untuk mok- Menangis semua interaksi layanan http eksternal
- Memeriksa tidak hanya skenario positif, tetapi juga negatif
Interaksi adalah beberapa interaksi REST atau SOAP http. Semua interaksi ini dalam kerangka tes yang kita ngompol. Artinya, dalam pengujian kami tidak ada daya tarik nyata untuk sistem eksternal di mana saja. Ini membuat tes stabil. Karena layanan eksternal dapat bekerja, mungkin tidak berfungsi, dapat merespons dengan lambat, mungkin dengan cepat, secara umum, tidak tahu apa perilakunya. Karena itu, kami menutup semuanya dengan moks.
Kami juga punya aturan seperti itu. Kami tidak hanya membasahi interaksi positif, tetapi juga mencoba memeriksa beberapa kasus negatif. Misalnya, ketika layanan pihak ketiga merespons dengan kesalahan ke-500 atau menghasilkan beberapa kesalahan yang lebih bermakna, kami mencoba memeriksa semuanya.
Kami menggunakan Wiremock untuk mengejek, Codeception sendiri mendukung ..., ia memiliki add-on resmi seperti Httpmock, tetapi kami lebih menyukai Wiremock. Bagaimana cara kerjanya?
Wiremock naik sebagai wadah Docker terpisah selama pengujian, dan semua permintaan yang harus pergi ke sistem eksternal pergi ke Wiremock.

Wiremock, jika Anda melihat slide - ada kotak seperti itu, Pemetaan Permintaan, ia memiliki seperangkat pemetaan yang mengatakan bahwa jika permintaan seperti itu datang, Anda perlu memberikan jawaban seperti itu. Semuanya sangat sederhana: permintaan datang - menerima tiruan.
Mengolok-olok dapat dibuat secara statis, maka wadah, ketika sudah dengan Wiremock naik, mengolok-olok ini akan tersedia, mereka dapat digunakan dalam pengujian manual. Anda dapat membuat secara dinamis, tepat di kode, dalam beberapa jenis tes.
Berikut ini adalah contoh cara membuat tiruan secara dinamis, Anda tahu, uraiannya cukup deklaratif, segera jelas dari kode jenis tiruan yang kita buat: tiruan untuk metode GET yang datang ke URL seperti itu, dan, pada kenyataannya, apa yang harus dikembalikan.

Selain fakta bahwa tiruan ini dapat dibuat, Wiremock memiliki kesempatan kemudian untuk memeriksa permintaan mana yang masuk ke tiruan ini. Ini juga sangat berguna dalam tes.
Tentang Codeception itu sendiri, mungkin, segalanya, dan beberapa kata tentang bagaimana pengujian kami dijalankan, dan sedikit infrastruktur.
Apa yang kita gunakan

Yah, pertama, semua layanan yang kami miliki di Docker, jadi meluncurkan lingkungan pengujian meningkatkan wadah yang tepat.
Make digunakan untuk perintah internal, Bamboo digunakan sebagai CI.
Seperti apa tampilan uji CI?

Pertama, kami membangun versi aplikasi yang diinginkan, kemudian kami meningkatkan lingkungan - ini adalah aplikasi, semua layanan yang dibutuhkan, seperti Kafka, Kelinci, basis data, dan kami memutar migrasi ke basis data.
Semua lingkungan ini dimunculkan dengan bantuan Docker Compose. Berada di CI, pada prod bahwa semua kontainer berputar di bawah Kubernetes. Kemudian jalankan tes dan jalankan.
Berapa lama waktu yang dibutuhkan?
Itu semua tergantung pada layanan spesifik, tetapi, sebagai suatu peraturan, meningkatkan lingkungan sebelum menjalankan tes adalah 5-10 menit, tes - dari 6 hingga 30 menit.

Saya akan segera memperingatkan pertanyaan ini saat semua tes mengejar dalam satu utas.
Nah, pertanyaan seperti itu. Seberapa sering tes harus dijalankan? Tentu saja, semakin sering, semakin baik. Semakin cepat Anda menangkap masalah, semakin cepat Anda bisa menyelesaikannya.
Kami memiliki 2 aturan utama. Ketika tugas masuk ke pengujian, semua tes, baik unit dan bukan unit tes, harus diteruskan. Jika beberapa tes gagal, ini adalah kesempatan untuk mentransfer tugas untuk diperbaiki.Wajar bila kami meluncurkan rilisnya. Pada rilis, semua tes harus lulus.Pada akhirnya, saya ingin mengatakan sesuatu yang menginspirasi - menulis tes, biarkan mereka menjadi hijau, gunakan Codeception, buat moki. Saya pikir Anda semua mengerti ini.