2014-01-14 3 views
5

Нормальное поведение let состоит в том, чтобы по существу привязываться к блоку примера (т. Е. Блокировать). Это нормально в большинстве случаев, но может представлять серьезные проблемы, если вы создаете большие объекты, используется в нескольких примерах. В этом случае переменная экземпляра почти становится необходимостью для разумности набора тестов.RSPEC Let Alternate Scoping

Время будет соединение как таковое:

  • пусть = # примеры называются в момент создания * объекта
  • время экземпляр = создание объекта

В тех случаях, когда число примеров, называемых в превышает 3, на этот раз быстро становится проблемой.

Большинство из них сказали бы, что использование переменных экземпляра - это ересь, но с нынешним состоянием, пусть это кажется чрезмерно догматичным бредни без особых исследований об обратном. Из любых статей, которые я прочитал в поддержку let, единственный аргумент - это призыв к ленивым проблемам загрузки и обзора, оба из которых не имеют отношения к хорошо написанным тестам.

Lazy loading, похоже, не имеет смысла в тестировании, поскольку это полезно только тогда, когда вы не уверены, нужны ли вам данные. Если это так, почему вы пытаетесь собрать данные в первую очередь для этого теста?

Если вы не мутируете объекты в своих тестах (подсказка: вы никогда не должны ее заглушать), тогда переменная экземпляра, вероятно, никогда не будет проблемой. Если это так, то соединение не является ошибкой переменной, оно само испытание.

TL; DR: Известен ли способ привязать оператор типа let к области альтернативного блока? В идеале я хотел бы привязать его как к описанию, так и к контекстным блокам, чтобы смягчить эту проблему.

Пример:

describe 'Person' do 
    local_bind let(:person) { Person.new(actual_data) } 

    context 'It has no data' do 
    local_bind let(:person) { Person.new(blank_data) } 
    # tests 
    end 
end 

В котором local_bind бы связать пусть текущий контекст блока, а не на примерах, в которых он работает. Конечно, это спекулятивный синтаксис, но дает общую идею здесь.

Это позволило бы объявить объект, который будет использоваться во всех примерах, которые находятся внутри области блока, что резко сократило бы негативные последствия, например, только memoization.

Хотя эти вопросы не будут иметь тенденцию к явно проявляется на основных объектах (50 вызовов * 0,001 экземпляров по-прежнему довольно быстро) он будет вопиюще видно на более дорогие (50 вызовов * 0,1 = 5 сек.)

Я видел тех, которые занимают это задолго до этого, и когда они каким-то образом проникают в помощников по спецификациям и привыкают повсюду при плохой абстракции производительности, вы можете себе представить, как тестовый набор из 3500 тестов может быстро согнуть до колен. Разница, наблюдавшаяся до сих пор, составила 75% -ное сокращение времени, взятого с 8:15 до 1:57, из-за проблемы JSON, и когда я это сделаю, пусть исправить я оцениваю падение до суб-20 секунд. Работая над получением доказательств этого.

+1

Можете ли вы представить пример кода, который вы бы хотели сделать? – Eugene

+0

Можете ли вы также объяснить, как вы видите переменные экземпляра, избегающие времени создания объекта? Вы говорите об использовании 'before (: all)'? –

+0

В этом случае да. Раньше все были бы наиболее вероятным кандидатом на это. Мне не нравятся последствия и срыв, но на данном этапе это кажется наиболее жизнеспособным. Как упоминалось выше, оператор let будет кэшировать только по одному примеру, то есть он перезагружает всю совокупность данных для каждого примера, в который он вызывается. Если вы не изменяете переменные для тестов, переменные экземпляра существенно дешевле для широко используемых переменных , – baweaver

ответ

-1

https://github.com/rspec/rspec-core/issues/1246

Я обсуждал этот точный вопрос с командой Rspec ядра, и они не имеют никакого намерения прояснения этого несчастное соглашения об именовании. Вместо этого они, похоже, настаивают на том, что программисты не знают ничего лучшего и должны держаться за руки и получать их после. Часть работы, эта серия ...