Saya cenderung menggunakan sebelum blok untuk mengatur variabel contoh. Saya kemudian menggunakan variabel-variabel tersebut di seluruh contoh saya. Saya baru-baru ini datang let()
. Menurut dokumen RSpec, sudah biasa
... untuk menentukan metode pembantu memoized. Nilai akan di-cache di beberapa panggilan dalam contoh yang sama tetapi tidak di seluruh contoh.
Bagaimana ini berbeda dari menggunakan variabel instan di sebelum blok? Dan juga kapan Anda harus menggunakan let()
vs before()
?
Jawaban:
Saya selalu lebih suka
let
variabel instan karena beberapa alasan:nil
, yang dapat menyebabkan bug halus dan positif palsu. Karenalet
membuat metode, Anda akan mendapatkanNameError
ketika Anda salah mengeja, yang menurut saya lebih disukai. Itu membuatnya lebih mudah untuk refactor spesifikasi juga.before(:each)
kait akan dijalankan sebelum setiap contoh, bahkan jika contoh tersebut tidak menggunakan variabel instan apa pun yang ditentukan dalam hook. Ini biasanya bukan masalah besar, tetapi jika setup variabel instan membutuhkan waktu lama, maka Anda membuang-buang siklus. Untuk metode yang ditentukan olehlet
, kode inisialisasi hanya berjalan jika contoh memanggilnya.@
).let
dan menjagait
blok saya bagus dan pendek.Tautan terkait dapat ditemukan di sini: http://www.betterspecs.org/#let
sumber
let
untuk mendefinisikan semua objek dependen, danbefore(:each)
untuk mengatur konfigurasi yang diperlukan atau mock / stubs yang dibutuhkan oleh contoh. Saya lebih suka ini daripada yang besar sebelum kait berisi semua ini. Juga,let(:foo) { Foo.new }
kurang berisik (dan lebih tepatnya)before(:each) { @foo = Foo.new }
. Berikut adalah contoh bagaimana saya menggunakannya: github.com/myronmarston/vcr/blob/v1.7.0/spec/vcr/util/…NoMethodError
menerima peringatan, tapi YMMV.foo = Foo.new(...)
dan kemudian penggunafoo
pada baris selanjutnya. Kemudian, Anda menulis contoh baru dalam grup contoh yang sama yang juga membutuhkanFoo
instantiated dengan cara yang sama. Pada titik ini, Anda ingin refactor untuk menghilangkan duplikasi. Anda dapat menghapusfoo = Foo.new(...)
garis dari contoh Anda dan menggantinya dengan tanpalet(:foo) { Foo.new(...) }
mengubah cara contoh digunakanfoo
. Tetapi jika Anda refactor kebefore { @foo = Foo.new(...) }
Anda juga harus memperbarui referensi dalam contoh darifoo
ke@foo
.Perbedaan antara menggunakan contoh variabel dan
let()
bahwalet()
adalah malas-dievaluasi . Ini berarti bahwalet()
tidak dievaluasi sampai metode yang ditetapkan dijalankan untuk pertama kalinya.Perbedaan antara
before
danlet
adalah yanglet()
memberi Anda cara yang bagus untuk mendefinisikan sekelompok variabel dalam gaya 'cascading'. Dengan melakukan ini, spek terlihat sedikit lebih baik dengan menyederhanakan kode.sumber
let
jika Anda perlu sesuatu untuk dievaluasi setiap waktu? misalnya saya memerlukan model anak untuk hadir dalam database sebelum beberapa perilaku dipicu pada model induk. Saya tidak perlu merujuk model anak itu dalam tes, karena saya menguji perilaku model orang tua. Saat ini saya menggunakanlet!
metode ini, tetapi mungkin akan lebih eksplisit untuk meletakkan pengaturan itubefore(:each)
?Saya telah sepenuhnya mengganti semua penggunaan variabel instan dalam tes rspec saya untuk menggunakan let (). Saya telah menulis contoh kilat untuk seorang teman yang menggunakannya untuk mengajar kelas Rspec kecil: http://ruby-lambda.blogspot.com/2011/02/agile-rspec-with-let.html
Seperti beberapa jawaban lain di sini mengatakan, biarkan () malas dievaluasi sehingga hanya akan memuat yang membutuhkan pemuatan. Ini KERING spesifikasi dan membuatnya lebih mudah dibaca. Sebenarnya saya telah mem-porting kode let () Rspec untuk digunakan di controller saya, dengan style permata inherited_resource. http://ruby-lambda.blogspot.com/2010/06/stealing-let-from-rspec.html
Bersamaan dengan evaluasi malas, keuntungan lainnya adalah, dikombinasikan dengan ActiveSupport :: Concern, dan spec-support-behavior / load-everything-in, Anda dapat membuat spec mini-DSL Anda sendiri yang spesifik untuk aplikasi Anda. Saya sudah menulis yang untuk menguji terhadap sumber daya Rack dan RESTful.
Strategi yang saya gunakan adalah Factory-everything (via Machinist + Forgery / Faker). Namun, dimungkinkan untuk menggunakannya dalam kombinasi dengan sebelum (: masing-masing) blok untuk memuat pabrik ke seluruh set kelompok contoh, memungkinkan spesifikasi berjalan lebih cepat: http://makandra.com/notes/770-taking-keuntungan -of-rspec-s-let-in-sebelum-blok
sumber
# spec/friendship_spec.rb
dan# spec/comment_spec.rb
contohnya, tidakkah menurut Anda mereka membuatnya kurang mudah dibaca? Saya tidak tahu dari manausers
datangnya dan perlu menggali lebih dalam.let()
beberapa hari terakhir dan secara pribadi saya tidak melihat perbedaan, kecuali untuk keuntungan pertama yang disebutkan Myron. Dan saya tidak begitu yakin tentang melepaskan dan apa yang tidak, mungkin karena saya malas dan saya suka melihat kode dimuka tanpa harus membuka file lain. Terima kasih atas komentar andaPenting untuk diingat bahwa membiarkan malas dievaluasi dan tidak memasukkan metode efek samping di dalamnya jika tidak Anda tidak akan dapat mengubah dari membiarkan ke sebelumnya (: masing-masing) dengan mudah. Anda bisa menggunakan let! alih-alih membiarkannya dievaluasi sebelum setiap skenario.
sumber
Secara umum,
let()
ini adalah sintaks yang lebih bagus, dan ini menghemat Anda mengetik@name
simbol di semua tempat. Tapi, emptor peringatan! Saya telah menemukanlet()
juga memperkenalkan bug halus (atau setidaknya menggaruk kepala) karena variabel tidak benar-benar ada sampai Anda mencoba menggunakannya ... Katakan tanda dongeng: jika menambahkanputs
setelahlet()
untuk melihat bahwa variabel benar memungkinkan spec untuk lulus, tetapi tanpaputs
spesifikasi gagal - Anda telah menemukan kehalusan ini.Saya juga menemukan bahwa
let()
sepertinya tidak ada cache dalam semua keadaan! Saya menulisnya di blog saya: http://technicaldebt.com/?p=1242Mungkin hanya saya?
sumber
let
selalu mencatat nilai selama durasi satu contoh. Itu tidak menghafal nilai di beberapa contoh.before(:all)
, sebaliknya, memungkinkan Anda untuk menggunakan kembali variabel yang diinisialisasi dalam banyak contoh.let!
dirancang untuk. relishapp.com/rspec/rspec-core/v/2-6/docs/helper-methods/…biarkan fungsional karena pada dasarnya Proc. Juga di-cache.
Satu gotcha saya temukan langsung dengan let ... Dalam blok Spec yang mengevaluasi perubahan.
Anda harus memastikan untuk menelepon di
let
luar blok harapan Anda. yaitu Anda meneleponFactoryGirl.create
di blok let Anda. Saya biasanya melakukan ini dengan memverifikasi objek tetap ada.Kalau tidak, ketika
let
blok disebut pertama kali perubahan dalam database akan benar-benar terjadi karena kemalasan malas.Memperbarui
Hanya menambahkan catatan. Berhati-hatilah bermain golf kode atau dalam hal ini golf rspec dengan jawaban ini.
Dalam hal ini, saya hanya perlu memanggil beberapa metode yang merespon objek. Jadi saya memanggil
_.persisted?
metode _ pada objek sebagai kebenarannya. Yang saya coba lakukan adalah instantiate objek. Anda bisa menelepon kosong? atau nihil? terlalu. Intinya bukan ujian tetapi membawa objek kehidupan dengan menyebutnya.Jadi kamu tidak bisa refactor
menjadi
sebagai objek belum instantiated ... malas. :)
Perbarui 2
memanfaatkan let! sintaks untuk pembuatan objek instan, yang harus menghindari masalah ini sama sekali. Perhatikan bahwa itu akan mengalahkan banyak tujuan kemalasan dari let non banged.
Juga dalam beberapa kasus Anda mungkin benar-benar ingin memanfaatkan sintaks subjek alih-alih membiarkan karena dapat memberi Anda opsi tambahan.
sumber
Catatan untuk Joseph - jika Anda membuat objek database di a
before(:all)
mereka tidak akan ditangkap dalam transaksi dan Anda lebih cenderung meninggalkan cacat di database pengujian Anda. Gunakanbefore(:each)
sebagai gantinya.Alasan lain untuk menggunakan let dan evaluasi malasnya adalah agar Anda dapat mengambil objek yang rumit dan menguji masing-masing potongan dengan mengesampingkan let dalam konteks, seperti dalam contoh yang sangat dibuat-buat ini:
sumber
"sebelum" secara default menyiratkan
before(:each)
. Ref The Rspec Book, hak cipta 2010, halaman 228.saya menggunakan
before(:each)
untuk seed beberapa data untuk setiap grup contoh tanpa harus memanggillet
metode untuk membuat data di blok "it". Lebih sedikit kode dalam blok "it" dalam kasus ini.saya menggunakan
let
jika saya ingin beberapa data dalam beberapa contoh tetapi tidak pada yang lain.Baik sebelum dan membiarkan sangat bagus untuk KERINGAN blok "itu".
Untuk menghindari kebingungan, "biarkan" tidak sama dengan
before(:all)
. "Biarkan" mengevaluasi kembali metode dan nilainya untuk setiap contoh ("itu"), tetapi cache nilai di beberapa panggilan dalam contoh yang sama. Anda dapat membaca lebih lanjut di sini: https://www.relishapp.com/rspec/rspec-core/v/2-6/docs/helper-methods/let-and-letsumber
Suara dissenting di sini: setelah 5 tahun rspec saya tidak terlalu suka
let
.1. Evaluasi malas sering membuat pengaturan tes membingungkan
Menjadi sulit untuk berpikir tentang pengaturan ketika beberapa hal yang telah dinyatakan dalam pengaturan tidak benar-benar mempengaruhi keadaan, sementara yang lain.
Akhirnya, karena frustrasi seseorang hanya berubah
let
kelet!
(hal yang sama tanpa evaluasi malas) untuk mendapatkan kerja spesifikasi mereka. Jika ini berhasil bagi mereka, sebuah kebiasaan baru lahir: ketika spec baru ditambahkan ke suite yang lebih lama dan itu tidak berhasil, hal pertama yang penulis coba adalah menambahkan poni ke acaklet
panggilan .Segera semua manfaat kinerja hilang.
2. Sintaks khusus tidak biasa bagi pengguna non-rspec
Saya lebih suka mengajar Ruby kepada tim saya daripada trik rspec. Variabel instan atau panggilan metode berguna di mana-mana dalam proyek ini dan lainnya,
let
sintaks hanya akan berguna di rspec.3. "Manfaat" memungkinkan kita untuk dengan mudah mengabaikan perubahan desain yang baik
let()
bagus untuk dependensi mahal yang tidak ingin kita buat berulang kali. Ini juga berpasangan dengan baiksubject
, memungkinkan Anda untuk mengeringkan panggilan berulang ke metode multi-argumenKetergantungan yang mahal berulang kali, dan metode dengan tanda tangan besar adalah titik di mana kita bisa membuat kode lebih baik:
Dalam semua kasus ini, saya dapat mengatasi gejala tes sulit dengan balsem sihir rspec yang menenangkan, atau saya dapat mencoba mengatasi penyebabnya. Saya merasa seperti saya menghabiskan terlalu banyak dari beberapa tahun terakhir pada yang pertama dan sekarang saya ingin beberapa kode yang lebih baik.
Untuk menjawab pertanyaan awal: Saya lebih suka tidak melakukannya, tetapi saya masih menggunakan
let
. Saya sebagian besar menggunakannya untuk menyesuaikan dengan gaya tim lainnya (sepertinya kebanyakan programmer Rails di dunia sekarang jauh ke dalam sihir rspec mereka sehingga sangat sering). Kadang-kadang saya menggunakannya ketika saya menambahkan tes ke beberapa kode yang saya tidak punya kendali, atau tidak punya waktu untuk refactor ke abstraksi yang lebih baik: yaitu ketika satu-satunya pilihan adalah penghilang rasa sakit.sumber
Saya gunakan
let
untuk menguji tanggapan HTTP 404 saya di spesifikasi API saya menggunakan konteks.Untuk membuat sumber daya, saya menggunakan
let!
. Tetapi untuk menyimpan pengenal sumber daya, saya menggunakanlet
. Lihatlah seperti apa tampilannya:Itu membuat spesifikasi tetap bersih dan mudah dibaca.
sumber