Люди, здається, пояснили деякі основні способи їх відмінності, але пропустили 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_awesome
if, якщо 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 для тесту, яку вам потрібно робити лише один раз.
Сподіваюся, що це допомагає :)