Mempercepat tes RSpec dalam aplikasi Rails yang besar


91

Saya memiliki aplikasi Rails dengan lebih dari 2.000 contoh dalam tes RSpec saya. Tak perlu dikatakan, ini adalah aplikasi yang besar dan ada banyak hal yang harus diuji. Menjalankan pengujian ini pada tahap ini sangat tidak efisien dan karena memakan waktu lama, kami hampir putus asa untuk menulisnya sebelum meluncurkan versi baru. Saya menambahkan --profile ke spec.opts saya untuk menemukan contoh yang paling lama berjalan dan setidaknya ada 10 di antaranya yang membutuhkan waktu rata-rata 10 detik untuk dijalankan. Apakah itu normal di antara Anda ahli RSpec? Apakah 10 detik terlalu lama untuk satu contoh? Saya menyadari bahwa dengan 2.000 contoh, akan membutuhkan waktu yang tidak sepele untuk menguji semuanya secara menyeluruh - tetapi pada titik ini 4 jam agak menggelikan.

Waktu seperti apa yang Anda lihat untuk contoh terlama Anda? Apa yang dapat saya lakukan untuk memecahkan masalah spesifikasi saya yang ada untuk mengetahui kemacetan dan membantu mempercepat. Setiap menit akan sangat membantu saat ini.


1
Apakah tes integrasi tes lambat? Apakah mereka mencapai db? Jika ya, seberapa sering db dimuat ulang dan dapatkah Anda mengejek db?
Kaleb Pederson

1
Apakah Anda dapat menjalankan sebagian dari spesifikasi yang relevan dengan bagian apa yang sedang Anda kerjakan, seperti autotest SeattleRB? Apakah Anda memiliki server integrasi berkelanjutan yang dapat menjalankan semua pengujian?
Andrew Grimm

Ingatlah juga bahwa segala sesuatu itu relatif. Saya pernah mendengar "grrr, rangkaian pengujian kami membutuhkan waktu selamanya" untuk 20 menit ... dan 16-20 jam. Itu semua tergantung pada yang melihatnya. 10 detik untuk pengujian tertentu sering kali berarti pengujian unit yang telah menjadi pengujian integrasi seperti yang disebutkan di bawah ini.
Michael Durrant

Sebuah saran untuk jenis masalah ini: gunakan perftools.rbbersama dengan kerangka pengujian Anda untuk memahami apa yang menggunakan sebagian besar waktu Anda. Terima 10 panggilan teratas dan cobalah untuk menghilangkan / membaca sepintas. Kemudian ulangi, sampai bahagia.
aledalande

Jawaban:


118

10 detik adalah waktu yang sangat lama untuk menjalankan satu pengujian. Naluri saya adalah bahwa target spesifikasi Anda menjalankan pengujian unit dan integrasi pada saat yang bersamaan. Ini adalah hal yang umum terjadi pada proyek dan pada tahap tertentu, Anda perlu mengatasi hutang teknis ini jika Anda ingin menghasilkan lebih banyak, lebih cepat. Ada sejumlah strategi yang dapat membantu Anda melakukan ini ... dan saya akan merekomendasikan beberapa strategi yang telah saya gunakan di masa lalu.

1. Unit Terpisah Dari Tes Integrasi

Hal pertama yang akan saya lakukan adalah memisahkan unit dari tes integrasi. Anda dapat melakukannya dengan:

  1. Memindahkannya (ke folder terpisah di bawah direktori spesifikasi) - dan memodifikasi target rake
  2. Memberi tag pada mereka (rspec memungkinkan Anda menandai pengujian Anda)

Filosofinya adalah, Anda ingin bangunan reguler Anda cepat - jika tidak, orang tidak akan terlalu senang untuk sering menjalankannya. Jadi kembalilah ke wilayah itu. Jalankan pengujian reguler Anda dengan cepat, dan gunakan server integrasi berkelanjutan untuk menjalankan build yang lebih lengkap.

Tes integrasi adalah tes yang melibatkan dependensi eksternal (misalnya Database, WebService, Queue, dan beberapa orang akan membantah FileSystem). Tes unit hanya menguji item kode tertentu yang ingin Anda periksa. Ini harus berjalan cepat (9000 dalam 45 detik dimungkinkan), yaitu sebagian besar harus berjalan di memori.

2. Ubah Tes Integrasi Menjadi Tes Unit

Jika sebagian besar pengujian unit Anda lebih kecil dari rangkaian pengujian integrasi, Anda mengalami masalah. Artinya, ketidakkonsistenan akan mulai terlihat dengan lebih mudah. Jadi dari sini, mulailah membuat lebih banyak pengujian unit untuk menggantikan pengujian integrasi. Hal-hal yang dapat Anda lakukan untuk membantu dalam proses ini adalah:

  1. Gunakan kerangka kerja tiruan, bukan sumber daya sebenarnya. Rspec memiliki kerangka kerja tiruan bawaan.
  2. Jalankan rcov di rangkaian pengujian unit Anda. Gunakan itu untuk mengukur seberapa menyeluruh rangkaian pengujian unit Anda.

Setelah Anda memiliki pengujian unit yang tepat untuk menggantikan pengujian integrasi - hapus pengujian integrasi. Pengujian duplikat hanya memperburuk pemeliharaan.

3. Jangan Gunakan Perlengkapan

Perlengkapan itu jahat. Gunakan pabrik sebagai gantinya (masinis atau bot pabrik). Sistem ini dapat membuat grafik data yang lebih mudah beradaptasi, dan yang lebih penting, mereka dapat membuat objek dalam memori yang dapat Anda gunakan, daripada memuat sesuatu dari sumber data eksternal.

4. Tambahkan Cek Untuk Menghentikan Tes Unit Menjadi Tes Integrasi

Sekarang setelah Anda memiliki pengujian yang lebih cepat, saatnya untuk melakukan pemeriksaan agar BERHENTI ini terjadi lagi.

Ada perpustakaan yang catatan aktif patch monyet melempar kesalahan ketika mencoba mengakses database (UnitRecord).

Anda juga dapat mencoba memasangkan dan TDD yang dapat membantu memaksa tim Anda menulis tes lebih cepat karena:

  1. Seseorang sedang memeriksa - jadi tidak ada yang malas
  2. TDD yang tepat membutuhkan umpan balik yang cepat. Tes yang lambat hanya membuat semuanya menyakitkan.

5. Gunakan Perpustakaan Lain Untuk Mengatasi Masalah

Seseorang menyebutkan spork (mempercepat waktu muat untuk rangkaian pengujian di bawah rails3), hydra / parallel_tests - untuk menjalankan pengujian unit secara paralel (di beberapa inti).

Ini mungkin harus digunakan TERAKHIR. Masalah Anda yang sebenarnya ada di langkah 1, 2, 3. Selesaikan itu dan Anda akan berada dalam posisi yang lebih baik untuk menggunakan infrastruktur tambahan.


Jawaban yang bagus. Memang benar bahwa tidak ada alat tingkat lanjut yang dapat membantu menjalankan pengujian yang buruk dengan cepat. Jadi cobalah menulis hanya yang bagus.
Yura Omelchuk

5
Saya tidak setuju pada poin ketiga Anda bahwa Anda tidak boleh menggunakan perlengkapan. Jika digunakan dengan benar, mereka lebih cepat daripada pabrik karena Anda tidak harus membuat objek. Data Anda ada di sana, Anda tidak perlu membuatnya dengan setiap kasus uji.
Wallerjake

3
Ini tentang pabrik menjadi lebih cepat adalah lelucon, bukan?
Mike Szyndel


16

Untuk buku masak hebat tentang meningkatkan kinerja suite pengujian Anda, lihat presentasi Grease Your Suite .

Dia mendokumentasikan percepatan 45x dalam waktu proses rangkaian pengujian dengan memanfaatkan teknik seperti:


Saya suka tautannya, tapi bukan presentasinya. Kartu indeks untuk pidato seseorang adalah prompt bagi pembicara untuk mengisi inti presentasi.
Brian Maltzan

Presentasi ini sudah tidak ada. fast_context mempercepat beberapa blok seharusnya. quickerclip (tautan itu juga mati) tampaknya mempercepat penjepit kertas. Hydra tidak digunakan lagi untuk parallel_tests dan Gorgon. bootsnap memiliki tweak sistem file dan sekarang disertakan dengan Rails. Versi Ruby terbaru telah meningkatkan alokasi dan GC.
rep

5

Anda bisa menggunakan Spork. Ini memiliki dukungan untuk 2.3.x,

https://github.com/sporkrb/spork

atau ./script/spec_server yang mungkin berfungsi untuk 2.x

Anda juga dapat mengedit konfigurasi database (yang pada dasarnya mempercepat kueri database, dll.), Yang juga akan meningkatkan performa untuk pengujian.


Spork itu luar biasa. Ini juga berfungsi di Rails 3, dengan sedikit peretasan. Tetapi satu hal yang perlu diperhatikan dengan Spork on Rails 3 adalah tampaknya tidak mengambil perubahan dalam pengontrol, jadi Anda harus sering-sering memulai ulang. Tapi bagaimanapun, Spork benar-benar luar biasa, peningkatan kecepatan tesnya sangat signifikan.
AboutRuby

4
Spork hanya untuk mempercepat startup, bukan tes. Jadi dengan spesifikasi yang banyak, keuntungannya tidak signifikan.
Reactormonk

Bertentangan dengan komentar di atas, spork dapat digunakan untuk mempercepat pengujian serta memulai sesuai railscast railscasts.com/episodes/285-spork . Secara besar-besaran meningkatkan rangkaian pengujian rspec saya pada aplikasi yang sangat besar. (Dikurangi dari 192 detik menjadi 10 detik!)
jamesc

3

10 detik per contoh sepertinya waktu yang sangat lama. Saya belum pernah melihat spesifikasi yang membutuhkan waktu lebih dari satu detik, dan sebagian besar membutuhkan waktu lebih sedikit. Apakah Anda menguji koneksi jaringan? Menulis database? Sistem file menulis?

Gunakan tiruan dan rintisan sebanyak mungkin - mereka banyak lebih cepat daripada menulis kode yang mengenai database. Sayangnya, mengejek dan mematikan juga membutuhkan lebih banyak waktu untuk menulis (dan lebih sulit untuk dilakukan dengan benar). Anda harus menyeimbangkan waktu yang dihabiskan untuk menulis tes vs. waktu yang dihabiskan untuk menjalankan tes.

Saya setuju dengan komentar Andrew Grimm tentang melihat ke dalam sistem CI yang memungkinkan Anda untuk memparalelkan rangkaian pengujian Anda. Untuk sesuatu sebesar itu, mungkin itu satu-satunya solusi yang layak.


ya jika itu 10 detik saya akan membuat profil dan melihat di mana kemacetannya
rogerdpack

1
Saya memiliki proyek besar dan menjalankan tes rspec tunggal membutuhkan waktu hampir 15-20 detik.
ExiRe

2

Beberapa orang telah menyebutkan Hydra di atas. Kami telah menggunakannya dengan sukses besar di masa lalu. Saya baru-baru ini mendokumentasikan proses menyiapkan dan menjalankan hydra: http://logicalfriday.com/2011/05/18/faster-rails-tests-with-hydra/

Saya setuju dengan sentimen bahwa teknik semacam ini tidak boleh digunakan sebagai pengganti tes menulis yang terstruktur dengan baik dan cepat secara default.





Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.