Apa perbedaan antara let
dan before
blok di RSpec?
Dan kapan harus menggunakannya?
Apa pendekatan yang baik (membiarkan atau sebelum) dalam contoh di bawah ini?
let(:user) { User.make !}
let(:account) {user.account.make!}
before(:each) do
@user = User.make!
@account = @user.account.make!
end
Saya mempelajari posting stackoverflow ini
Tetapi apakah baik untuk mendefinisikan biarkan untuk hal-hal asosiasi seperti di atas?
ruby-on-rails
unit-testing
rspec
kriysna
sumber
sumber
Jawaban:
Orang-orang tampaknya telah menjelaskan beberapa cara dasar di mana mereka berbeda, tetapi ditinggalkan
before(:all)
dan tidak menjelaskan dengan tepat mengapa mereka harus digunakan.Saya yakin bahwa variabel instan tidak memiliki tempat untuk digunakan di sebagian besar spesifikasi, sebagian karena alasan yang disebutkan dalam jawaban ini , jadi saya tidak akan menyebutkannya sebagai opsi di sini.
biarkan blok
Kode dalam satu
let
blok hanya dieksekusi ketika direferensikan, pemuatan lambat ini berarti bahwa urutan blok-blok ini tidak relevan. Ini memberi Anda sejumlah besar daya untuk mengurangi penyiapan berulang melalui spesifikasi Anda.Salah satu contoh (sangat kecil dan dibuat-buat) ini adalah:
let(:person) { build(:person) } subject(:result) { Library.calculate_awesome(person, has_moustache) } context 'with a moustache' do let(:has_moustache) { true } its(:awesome?) { should be_true } end context 'without a moustache' do let(:has_moustache) { false } its(:awesome?) { should be_false } end
Anda dapat melihat
has_moustache
definisi yang berbeda di setiap kasus, tetapi tidak perlu mengulangisubject
definisi tersebut. Sesuatu yang penting untuk diperhatikan adalahlet
blok terakhir yang ditentukan dalam konteks saat ini akan digunakan. Ini bagus untuk menyetel default agar digunakan untuk sebagian besar spesifikasi, yang dapat ditimpa jika perlu.Misalnya, memeriksa nilai kembalian
calculate_awesome
jika meneruskanperson
model dengantop_hat
set ke true, tetapi tidak ada kumis akan menjadi:context 'without a moustache but with a top hat' do let(:has_moustache) { false } let(:person) { build(:person, top_hat: true) } its(:awesome?) { should be_true } end
Hal lain yang perlu diperhatikan tentang blok let, mereka tidak boleh digunakan jika Anda mencari sesuatu yang telah disimpan ke database (yaitu
Library.find_awesome_people(search_criteria)
) karena mereka tidak akan disimpan ke database kecuali mereka telah direferensikan.let!
ataubefore
balok adalah apa yang harus digunakan di sini.Juga, jangan pernah gunakan
before
untuk memicu eksekusilet
blok, inilah yanglet!
dibuat untuk!membiarkan! blok
let!
blok dieksekusi dalam urutan yang mereka definisikan (seperti blok sebelumnya). Satu perbedaan inti dengan blok before adalah Anda mendapatkan referensi eksplisit ke variabel ini, daripada harus kembali ke variabel instan.Seperti halnya
let
blok, jika beberapalet!
blok didefinisikan dengan nama yang sama, yang terbaru adalah apa yang akan digunakan dalam eksekusi. Perbedaan intinya adalahlet!
blok akan dieksekusi beberapa kali jika digunakan seperti ini, sedangkanlet
blok hanya akan dieksekusi terakhir kali.sebelum (: setiap) blok
before(:each)
adalah default sebelum blokir, dan oleh karena itu dapat direferensikanbefore {}
daripada menentukan secara penuhbefore(:each) {}
setiap saat.Ini adalah preferensi pribadi saya untuk menggunakan
before
blok dalam beberapa situasi inti. Saya akan menggunakan sebelum blok jika:before { get :index }
). Meskipun Anda dapat menggunakansubject
ini dalam banyak kasus, terkadang terasa lebih eksplisit jika Anda tidak memerlukan referensi.Jika Anda menemukan diri Anda menulis
before
blok besar untuk spesifikasi Anda, periksa pabrik Anda dan pastikan Anda memahami sepenuhnya sifat dan fleksibilitasnya.sebelum (: semua) blok
Ini hanya akan dieksekusi sekali, sebelum spesifikasi dalam konteks saat ini (dan turunannya). Ini dapat digunakan untuk keuntungan besar jika ditulis dengan benar, karena ada situasi tertentu yang dapat mengurangi eksekusi dan upaya.
Salah satu contoh (yang hampir tidak memengaruhi waktu eksekusi sama sekali) adalah mengejek variabel ENV untuk pengujian, yang seharusnya hanya perlu Anda lakukan sekali.
Semoga membantu :)
sumber
before(:all)
opsi tidak ada di Minitest. Berikut adalah beberapa solusi di komentar: github.com/seattlerb/minitest/issues/61its
tidak lagi dalam rspec-core. Cara yang lebih modern dan idiomatis adalahit { is_expected.to be_awesome }
.Hampir selalu, saya lebih suka
let
. Posting yang Anda tautkanlet
juga lebih cepat. Namun, terkadang, ketika banyak perintah harus dijalankan, saya dapat menggunakannyabefore(:each)
karena sintaksnya lebih jelas ketika banyak perintah yang terlibat.Dalam contoh Anda, saya pasti lebih suka menggunakan
let
daripadabefore(:each)
. Secara umum, ketika hanya beberapa inisialisasi variabel dilakukan, saya cenderung suka menggunakanlet
.sumber
Perbedaan besar yang belum disebutkan adalah bahwa variabel yang ditentukan dengan
let
tidak dibuat instance-nya sampai Anda memanggilnya pertama kali. Jadi, sementarabefore(:each)
blok akan membuat instance semua variabel,let
mari kita tentukan sejumlah variabel yang mungkin Anda gunakan di beberapa pengujian, itu tidak secara otomatis membuat instance-nya. Tanpa mengetahui hal ini, pengujian Anda dapat kembali gagal jika Anda mengharapkan semua data dimuat sebelumnya. Dalam beberapa kasus, Anda bahkan mungkin ingin menentukan sejumlahlet
variabel, kemudian menggunakanbefore(:each)
blok untuk memanggil setiaplet
contoh hanya untuk memastikan datanya tersedia untuk memulai.sumber
let!
untuk menentukan metode yang dipanggil sebelum setiap contoh. Lihat dokumen RSpec .Sepertinya Anda menggunakan Masinis. Waspadalah, Anda mungkin melihat beberapa masalah dengan make! di dalam let (versi non-bang) terjadi di luar transaksi perlengkapan global (jika Anda menggunakan perlengkapan transaksional juga) sehingga merusak data untuk pengujian Anda yang lain.
sumber