
Hai, saya Alexey, pengembang penuh platform Vimbox. Ketika saya datang ke Skyeng, mereka memutuskan di sini apakah sepadan dengan waktu yang dihabiskan untuk sistem autotest dan meminta saya untuk membagikan pengalaman saya dari pekerjaan sebelumnya. Dan saya memiliki pengalaman seperti itu: pada saat kami meninggalkan tempat sebelumnya, kami menulis dalam php dan memutar lebih dari 3 ribu tes. Sebagai hasilnya, saya membuat presentasi internal kecil yang menceritakan tentang rake yang berhasil saya kembangkan dalam beberapa tahun mengembangkan tes-otomatis ini, berjuang untuk kecepatan, keterbacaan kode, dan efisiensi keseluruhan. Presentasi itu tampaknya bermanfaat bagi rekan kerja, jadi saya memasukkannya ke dalam teks agar bermanfaat juga untuk khalayak yang lebih luas.
Untuk memulainya, istilah yang akan dibahas dalam artikel:
- Tes penerimaan - tes ujung ke ujung: di sini browser atau emulator browser menjalankan skrip
- Uji unit ( uji unit) - uji metode
- Tes fungsional - tes controller atau komponen, ketika datang ke frontend
- Fixture - keadaan lingkungan pengujian yang diperlukan agar tes dapat berfungsi (variabel global, data dalam database, dan peserta lain dalam skrip tes)
Pro dan kontra dari berbagai jenis tes

Tes penerimaan
- Pro: jelas dari namanya, tes tersebut mencakup seluruh sistem dari atas ke bawah, pastikan semuanya bekerja sebagaimana mestinya.
- Kontra: umpan balik dari tes ini sangat lambat, mereka bekerja untuk waktu yang lama, mereka tidak terlalu dapat diandalkan, ada banyak positif palsu. Pada pekerjaan sebelumnya, kami juga dihadapkan dengan fakta bahwa driver web tidak mendeteksi beberapa elemen yang kami lihat dengan mata kami. Sekarang ini mungkin sudah diperbaiki, tetapi kemudian saya harus meninggalkan mereka.
Tes unit
- Pro: mudah untuk menulis, bekerja dengan cepat. Mereka mencakup sepotong kode kecil, Anda tidak perlu banyak negara, oleh karena itu, Anda tidak perlu perlengkapan besar juga.
- Cons: tidak stabil terhadap perubahan dalam arsitektur atau struktur internal kode. Jika Anda perlu menggabungkan dua metode menjadi satu atau terpisah, pilih kelas, hapus metode, Anda harus menulis ulang tes.
Tes fungsional adalah solusi perantara.
- Kelebihan: penerimaan yang lebih andal, lebih tahan terhadap perubahan dalam struktur kode daripada modular.
- Cons: lebih lambat daripada modular, lebih sulit untuk menulis, karena perlu menyiapkan perlengkapan besar.
Perjuangan untuk kecepatan
Di pekerjaan lama, kami menulis banyak tes fungsional, dan tantangan utama adalah kecepatan respon. Saya harus menunggu lama untuk hasilnya, bahkan dengan peluncuran lokal di komputer pengembang. Kecepatannya sangat lambat sehingga tidak mungkin untuk menerapkan pendekatan "pengembangan melalui pengujian", karena itu melibatkan menjalankan autotest beberapa kali per jam. Menemukan hambatan - bekerja dengan database. Bagaimana cara mengatasinya?
Pengalaman pertama: moki
Mock di PhpUnit adalah objek yang dibuat secara dinamis yang kelasnya secara dinamis diwarisi dari kelas yang diparodikan. Anda dapat mengkonfigurasi metode apa yang akan dikembalikan oleh mok, Anda dapat memeriksa metode mana dari moq berapa kali parameter yang dipanggil
Plus utama dari moki - mereka memungkinkan Anda untuk memotong seluruh fungsionalitas. Mengganti layanan dengan moch, kami menyingkirkan kebutuhan untuk memikirkan apa yang terjadi di sana, untuk mengembangkan skrip dan perlengkapan tambahan sehingga semuanya berfungsi dengan benar. Akibatnya: lebih sedikit perlengkapan, dan kecepatan respons lebih tinggi karena fakta bahwa kami memotong kode tambahan yang mengeksekusi kueri ke database.
Nilai plus dari massa adalah bahwa mereka membuat lebih baik untuk mengatur kecanduan. Ketika Anda menulis kode, mengetahui bahwa akan diperlukan untuk menulis tes di atasnya, di mana ada sesuatu yang digantikan oleh mokami, Anda segera memikirkan dependensi.
Minus : kode tes terlalu melekat pada implementasi. Selama pengujian, kita harus membuat objek tiruan dan berpikir tentang metode apa yang harus dipanggil.
Kekurangan kedua yang ditemukan adalah bahwa tes menjadi kurang dapat diandalkan. Mereka “tidak memperhatikan” bahkan perubahan pada antarmuka, belum lagi implementasinya. Yaitu kami menghapus metode di suatu tempat dan setelah waktu yang lama menemukan bahwa tes yang menutupinya masih berfungsi seolah-olah tidak ada yang terjadi, karena kami melihat tiruannya, dan dia berpura-pura semuanya baik-baik saja.
Saya menganggap pengalaman dengan mokas tidak berhasil dalam hal mempercepat tes.
Pengalaman Dua: SQLite
Opsi selanjutnya adalah SQLite DBMS , dapat membuat database dalam RAM. Saya harus menulis skema penerjemah PostgreSQL dalam SQLite, setelah setiap migrasi skema SQLite baru dihasilkan. Tes dari sirkuit ini membuat database kosong dalam RAM. Pendekatan ini meningkatkan kecepatan pengujian pada mesin lokal sebanyak dua hingga empat kali. Menjadi realistis untuk menjalankan seluruh rangkaian tes beberapa kali per jam.
Tapi ada kontra. Kami telah kehilangan banyak fitur PostgreSQL asli (json, beberapa fungsi agregat praktis, dan banyak lagi). Pertanyaan harus ditulis sehingga mereka bekerja pada PostgreSQL dan SQLite.
Pengalaman Tiga: Optimasi PostgreSQL
Keputusan ini berhasil, tetapi menimbulkan rasa sakit. Pada titik tertentu, kami mengetahui bahwa PostgreSQL dapat dioptimalkan untuk autotest, yang mengurangi waktu respons sekitar empat kali. Untuk melakukan ini, tambahkan beberapa pengaturan ke postgresql.conf:
fsync=off synchronous_commit=off full_page_writes=off
Ini adalah pengaturan keandalan, mereka menjamin bahwa jika server mati di tengah transaksi, itu akan selesai dengan benar ketika semuanya mulai berfungsi lagi. Jelas bahwa pengaturan seperti itu tidak dapat dibuat pada produksi, tetapi nyaman pada pengujian otomatis.
Pengaturan ini diterapkan ke seluruh kluster, memengaruhi semua basis data, tidak dapat diterapkan ke satu basis data. Jika Anda berhasil melokalkan basis data dalam gugus terpisah dan menonaktifkan fsync di dalamnya, ini sangat nyaman.
Sedikit tentang yang new
Saya juga ingin menyebutkan bahaya dari operator new
. Layanan yang dibuat dengan bantuannya tidak dapat digantikan oleh moka dan bertopik. Kesimpulan:
- Jangan gunakan yang
new
untuk membuat objek yang pada dasarnya adalah layanan. - Ini dapat digunakan di pabrik, karena dapat diganti. Tetapi pabrik itu sendiri tidak boleh diciptakan melalui yang
new
. - Dapat digunakan untuk membuat model, entitas, DTO (objek transfer data), nilai-objek.
Kesimpulan dari pengalaman tiga tahun
- Pada pekerjaan sebelumnya, kami menolak tes penerimaan, tetapi sekarang saya akan mencobanya lagi: kemungkinan besar banyak bug diperbaiki pada driver web.
- Jika Anda perlu membahas fungsionalitas baru dengan tes, Anda hanya perlu menulis tes fungsional controller / komponen. Dalam situasi ini, kami memiliki risiko tinggi terhadap perubahan struktural, unit test tidak stabil untuk mereka.
- Seharusnya tidak ada banyak tes seperti itu, karena banyak == lambat, mereka tidak bekerja secepat yang modular. Layak hanya mencakup kasus-kasus yang dapat "menembak" (mereka memiliki kemungkinan kesalahan di masa depan).
- Tes unit ditulis pada metode kaya algoritmik (logika kompleks yang perlu diuji) atau pada metode dengan sedikit risiko perubahan struktural di masa depan.
- Kontra moka umumnya melebihi pro. Masuk akal untuk menggunakannya hanya sebagai pengganti gateway ke API eksternal, dan kadang-kadang layanan dari kode lama, yang sangat sulit untuk diuji.
- Jika Anda memutuskan untuk menulis kode tanpa tes, disarankan untuk berpikir, "ketika Anda membuatnya, bagaimana jika di masa depan kita masih ingin menulis tes untuk itu?"
- Tes harus mudah dan menyenangkan untuk ditulis, mereka memberikan keandalan, kepercayaan diri, membantu untuk lebih memahami kode, mengelola dependensi.
- Perhatikan keterbacaan tes. Seseorang harus berhubungan dengan kode tes dengan cara yang sama dengan kode yang dicakupnya.
- Perlengkapan DB - bagian dari tes, juga harus dapat dibaca