RSpec: В чем разница между let и блоком before? - PullRequest
85 голосов
/ 12 мая 2011

В чем разница между let и before блоком в RSpec?

А когда использовать каждый?

Что будет хорошим подходом (пусть или до) в следующем примере?

let(:user) { User.make !}
let(:account) {user.account.make!}

before(:each) do
 @user = User.make!
 @account = @user.account.make!
end

Я изучил это сообщение stackoverflow

Но хорошо ли определять let для ассоциативных вещей, как указано выше?

Ответы [ 4 ]

134 голосов
/ 27 марта 2013

Люди, кажется, объяснили некоторые основные отличия, но не указали 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 для теста, который вам нужно будет выполнить только один раз.

Надеюсь, это поможет:)

25 голосов
/ 12 мая 2011

Почти всегда я предпочитаю let. Пост, на который вы ссылаетесь, указывает, что let также быстрее. Однако иногда, когда нужно выполнить много команд, я мог бы использовать before(:each), потому что его синтаксис более понятен, когда задействовано много команд.

В вашем примере я бы определенно предпочел использовать let вместо before(:each). Вообще говоря, когда выполняется только некоторая инициализация переменной, мне нравится использовать let.

15 голосов
/ 09 января 2012

Большим отличием, которое не было упомянуто, является то, что переменные, определенные с let, не создаются, пока вы не вызовете его в первый раз. Таким образом, в то время как блок before(:each) создает все переменные, let позволяет вам определить количество переменных, которые вы можете использовать в нескольких тестах, он не создает их автоматически. Не зная этого, ваши тесты могут вернуться к вам, если вы ожидаете, что все данные будут загружены заранее. В некоторых случаях вам может даже потребоваться определить число let переменных, а затем использовать блок before(:each) для вызова каждого экземпляра let, просто чтобы убедиться, что данные доступны для начала.

3 голосов
/ 03 августа 2011

Похоже, вы используете Машинист. Осторожно, вы можете увидеть некоторые проблемы с make! внутри let (версия без взрыва), происходящая вне глобальной транзакции фикстуры (если вы также используете транзакционные фикстуры), что повреждает данные для других ваших тестов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...