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