Люди, здається, пояснили деякі основні способи їх відмінності, але пропустили before(:all)і не пояснюють, чому саме їх слід використовувати.
Я вважаю, що змінні екземпляри не мають місця для використання в переважній більшості специфікацій, частково через причини, згадані в цій відповіді , тому я не буду згадувати їх як варіант тут.
нехай блоки
Код всередині letблоку виконується лише при посиланні, ліниве завантаження це означає, що впорядкування цих блоків не має значення. Це дає вам велику кількість енергії, щоб скоротити повторне налаштування за допомогою специфікацій.
Одним із надзвичайно малих та надуманих прикладів є:
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
Ви можете бачити, що has_moustacheв кожному випадку це визначається по-різному, але немає потреби повторювати subjectвизначення. Щось важливе, на що слід звернути увагу, це те, що буде використаний останній letблок, визначений у поточному контексті. Це добре для встановлення типового значення для більшості специфікацій, яке при необхідності може бути замінено.
Наприклад, перевірка поверненого значення calculate_awesomeif, якщо personмодель передається із top_hatзначенням true, але жоден вус не буде:
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
Ще одне, на що слід звернути увагу, щодо блоків let, їх не слід використовувати, якщо ви шукаєте щось, що було збережено в базі даних (тобто Library.find_awesome_people(search_criteria)), оскільки вони не будуть збережені в базі даних, якщо на них вже не зроблено посилання. let!або beforeблоки - це те, що тут слід використовувати.
Крім того, ніколи не використовуйте beforeдля запуску виконання letблоків, саме для цього let!створено!
дозволяти! блоків
let!блоки виконуються в тому порядку, в якому вони визначені (приблизно як блок до). Однією з основних відмінностей блоків before є те, що ви отримуєте явне посилання на цю змінну, а не потребуєте повернення до змінних екземпляра.
Як і у випадку з letблоками, якщо декілька let!блоків визначено з однаковим іменем, останнім буде те, що буде використано у виконанні. Основна різниця полягає в тому, що let!блоки будуть виконуватися кілька разів, якщо використовувати їх таким чином, тоді як letблок буде виконуватися лише востаннє.
перед блоками (: кожен)
before(:each)є типовим перед блоком, і тому на нього можна посилатись, before {}а не вказати повний before(:each) {}раз.
Це моя особиста перевага використовувати beforeблоки в декількох основних ситуаціях. Я буду використовувати перед блоками, якщо:
- Я використовую знущання, тупіння або подвійні
- Існує будь-яка установка розумного розміру (як правило, це ознака того, що ваші заводські якості були встановлені неправильно)
- Існує ряд змінних, на які мені не потрібно посилатися безпосередньо, але вони потрібні для налаштування
- Я пишу тести функціональних контролерів на рейках і хочу виконати конкретний запит на тестування (тобто
before { get :index }). Незважаючи на те, що ви могли б використовувати subjectце для багатьох випадків, іноді це здається більш чітким, якщо вам не потрібна довідка.
Якщо ви виявите, що пишете великі beforeблоки для своїх специфікацій, перевірте свої заводи та переконайтеся, що ви повністю розумієте риси та їх гнучкість.
перед (: усі) блоками
Вони виконуються лише один раз, до специфікацій у поточному контексті (та його потомків). Вони можуть бути використані з великою перевагою, якщо вони написані правильно, оскільки в певних ситуаціях це може скоротити виконання та зусилля.
Одним з прикладів (який навряд чи взагалі вплине на час виконання) є висміювання змінної ENV для тесту, яку вам потрібно робити лише один раз.
Сподіваюся, що це допомагає :)