Saya menguji model dengan callback setelah membuat yang saya ingin jalankan hanya pada beberapa kesempatan saat menguji. Bagaimana cara melewati / menjalankan panggilan balik dari pabrik?
class User < ActiveRecord::Base
after_create :run_something
...
end
Pabrik:
FactoryGirl.define do
factory :user do
first_name "Luiz"
last_name "Branco"
...
# skip callback
factory :with_run_something do
# run callback
end
end
ruby-on-rails
rspec
factory-bot
luizbranco
sumber
sumber
:on => :create
validasi, gunakanafter(:build) { |user| user.class.skip_callback(:validate, :create, :after, :run_something) }
Class.skip_callback
panggilan tersebut akan tetap ada di seluruh pengujian lainnya, jadi jika pengujian Anda yang lain mengharapkan callback terjadi, pengujian tersebut akan gagal jika Anda mencoba membalik logika callback melewatkan.after(:build)
blok. Ini memungkinkan default pabrik Anda untuk menjalankan panggilan balik dan tidak perlu menyetel ulang panggilan balik setelah setiap penggunaan.Jika Anda tidak ingin menjalankan callback, lakukan hal berikut:
Ketahuilah bahwa skip_callback akan tetap ada di spesifikasi lain setelah dijalankan oleh karena itu pertimbangkan sesuatu seperti berikut:
sumber
Tak satu pun dari solusi ini yang bagus. Mereka merusak kelas dengan menghapus fungsionalitas yang harus dihapus dari instance, bukan dari kelas.
Alih-alih menekan callback, saya menyembunyikan fungsionalitas callback. Di satu sisi, saya lebih menyukai pendekatan ini karena lebih eksplisit.
sumber
around_*
(misalnyauser.define_singleton_method(:around_callback_method){|&b| b.call }
).Saya ingin menyempurnakan jawaban @luizbranco agar callback after_save lebih dapat digunakan kembali saat membuat pengguna lain.
Berjalan tanpa callback after_save:
Berjalan dengan callback after_save:
Dalam pengujian saya, saya lebih suka membuat pengguna tanpa callback secara default karena metode yang digunakan menjalankan hal-hal tambahan yang biasanya tidak saya inginkan dalam contoh pengujian saya.
---------- UPDATE ------------ Saya berhenti menggunakan skip_callback karena ada beberapa masalah inkonsistensi dalam rangkaian pengujian.
Solusi Alternatif 1 (penggunaan stub dan unstub):
Solusi Alternatif 2 (pendekatan pilihan saya):
sumber
Rails 5 -
skip_callback
memunculkan kesalahan Argument saat melompati dari pabrik FactoryBot.Ada perubahan di Rails 5 dengan cara skip_callback menangani callback yang tidak dikenal:
Saat
skip_callback
dipanggil dari pabrik, callback sebenarnya dalam model AR belum ditentukan.Jika Anda telah mencoba semuanya dan menarik rambut Anda seperti saya, inilah solusi Anda (dapatkan dari mencari masalah FactoryBot) ( CATATAN
raise: false
bagiannya ):Jangan ragu untuk menggunakannya dengan strategi lain apa pun yang Anda sukai.
sumber
Solusi ini berfungsi untuk saya dan Anda tidak perlu menambahkan blok tambahan ke definisi Pabrik Anda:
sumber
Sebuah rintisan sederhana bekerja paling baik untuk saya di Rspec 3
sumber
User
;:run_something
bukanlah metode kelas.Catatan penting Anda harus menentukan keduanya. Jika hanya digunakan sebelum dan menjalankan beberapa spesifikasi, itu akan mencoba menonaktifkan callback beberapa kali. Ini akan berhasil pertama kali, tetapi yang kedua, panggilan balik tidak akan ditentukan lagi. Jadi itu akan error
sumber
Memanggil skip_callback dari pabrik saya terbukti bermasalah bagi saya.
Dalam kasus saya, saya memiliki kelas dokumen dengan beberapa panggilan balik terkait s3 sebelum dan sesudah membuat yang saya hanya ingin menjalankan ketika menguji tumpukan penuh diperlukan. Jika tidak, saya ingin melewati callback s3 tersebut.
Ketika saya mencoba skip_callbacks di pabrik saya, panggilan balik itu tetap bertahan bahkan ketika saya membuat objek dokumen secara langsung, tanpa menggunakan pabrik. Jadi sebagai gantinya, saya menggunakan mocha stub di panggilan build setelah dan semuanya bekerja dengan sempurna:
sumber
before_validation
hook (mencoba melakukanskip_callback
dengan salah satu FactoryGirlbefore
atauafter
opsi untukbuild
dancreate
tidak berfungsi)Ini akan bekerja dengan sintaks rspec saat ini (pada posting ini) dan jauh lebih bersih:
sumber
Jawaban James Chevalier tentang cara melewati panggilan balik before_validation tidak membantu saya jadi jika Anda mengalami hal yang sama seperti saya, berikut ini solusi yang berfungsi:
dalam model:
di pabrik:
sumber
Model.skip_callback(...)
Dalam kasus saya, saya memiliki panggilan balik memuat sesuatu ke cache redis saya. Namun kemudian saya tidak memiliki / ingin instance redis berjalan untuk lingkungan pengujian saya.
Untuk situasi saya, mirip dengan di atas, saya baru saja menghentikan
load_to_cache
metode saya di spec_helper saya, dengan:Juga, dalam situasi tertentu di mana saya ingin menguji ini, saya hanya perlu melepasnya di blok sebelumnya dari kasus uji Rspec yang sesuai.
Saya tahu Anda mungkin mengalami sesuatu yang lebih rumit dalam diri Anda
after_create
atau mungkin tidak menganggap ini sangat elegan. Anda dapat mencoba membatalkan callback yang ditentukan dalam model Anda, dengan menentukanafter_create
hook di Pabrik Anda (lihat dokumen factory_girl), di mana Anda mungkin dapat menentukan callback dan return yang samafalse
, sesuai dengan bagian 'Membatalkan callback' di artikel ini . (Saya tidak yakin tentang urutan eksekusi callback, itulah sebabnya saya tidak memilih opsi ini).Terakhir, (maaf saya tidak dapat menemukan artikelnya) Ruby memungkinkan Anda menggunakan beberapa program meta kotor untuk melepaskan kait panggilan balik (Anda harus mengatur ulang). Saya kira ini akan menjadi opsi yang paling tidak disukai.
Ada satu hal lagi, sebenarnya bukan solusi, tetapi lihat apakah Anda bisa lolos dengan Factory.build dalam spesifikasi Anda, daripada benar-benar membuat objek. (Akan menjadi yang paling sederhana jika Anda bisa).
sumber
Mengenai jawaban yang diposting di atas, https://stackoverflow.com/a/35562805/2001785 , Anda tidak perlu menambahkan kode ke pabrik. Saya merasa lebih mudah untuk membebani metode dalam spesifikasi itu sendiri. Misalnya, alih-alih (dalam hubungannya dengan kode pabrik di pos yang dikutip)
Saya suka menggunakan (tanpa kode pabrik yang dikutip)
Dengan cara ini Anda tidak perlu melihat ke pabrik dan file pengujian untuk memahami perilaku pengujian.
sumber
Saya menemukan solusi berikut menjadi cara yang lebih bersih karena callback dijalankan / disetel pada tingkat kelas.
sumber
Berikut cuplikan yang saya buat untuk menangani ini dengan cara yang umum.
Ini akan melewati setiap callback yang dikonfigurasi, termasuk callback yang berhubungan dengan rails
before_save_collection_association
, tetapi tidak akan melewatkan beberapa hal yang diperlukan untuk membuat ActiveRecord berfungsi dengan baik, sepertiautosave_associated_records_for_
callback yang dibuat secara otomatis .lalu nanti:
Tentu saja, YMMV, jadi lihat di log pengujian apa yang sebenarnya Anda lewati. Mungkin Anda memiliki permata yang menambahkan panggilan balik yang benar-benar Anda butuhkan dan itu akan membuat pengujian Anda gagal total atau dari 100 model gemuk panggilan balik Anda, Anda hanya perlu pasangan untuk tes tertentu. Untuk kasus tersebut, coba transient
:force_callbacks
BONUS
Terkadang Anda juga perlu melewati validasi (semua dalam upaya untuk membuat tes lebih cepat), lalu coba dengan:
sumber
Anda bisa menyetel callback dengan sifat untuk instance tersebut saat Anda ingin menjalankannya.
sumber