Люди, кажется, объяснили некоторые основные отличия, но не указали 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
, если передана модель 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). Основное отличие от блоков before заключается в том, что вы получаете явную ссылку на эту переменную, а не на необходимость обращаться к переменным экземпляра.
Как и в случае блоков let
, если несколько блоков let!
определены с одним и тем же именем, самое последнее будет использовано при выполнении. Основным отличием является то, что блоки let!
будут выполняться несколько раз, если используются таким образом, тогда как блок let
будет выполняться только в последний раз.
до (: каждый) блоков
before(:each)
является блоком перед блоком по умолчанию, поэтому на него можно ссылаться как before {}
, а не указывать полный before(:each) {}
каждый раз.
Я лично предпочитаю использовать блоки before
в нескольких основных ситуациях. Я буду использовать перед блоками, если:
- Я использую насмешки, удары или двойники
- Есть разумные размеры (обычно это признак того, что ваши заводские черты не были правильно настроены)
- Существует ряд переменных, на которые мне не нужно ссылаться напрямую, но они требуются для настройки
- Я пишу тесты функциональных контроллеров в рельсах и хочу выполнить конкретный запрос на тестирование (т. Е.
before { get :index }
). Несмотря на то, что вы могли бы использовать subject
для этого во многих случаях, иногда это кажется более явным, если вам не нужна ссылка.
Если вы обнаружите, что пишете большие before
блоки для своих спецификаций, проверьте свои фабрики и убедитесь, что вы полностью понимаете особенности и их гибкость.
перед (: все) блоками
Они выполняются только один раз, перед спецификациями в текущем контексте (и его дочерними элементами). Их можно использовать с большой выгодой, если они написаны правильно, поскольку в определенных ситуациях это может сократить выполнение и усилие.
Одним из примеров (который вряд ли повлияет на время выполнения) является макетирование переменной ENV для теста, который вам нужно будет выполнить только один раз.
Надеюсь, это поможет:)