Вы неправильно используете этот материал, и я понимаю ваше разочарование.Итак, позвольте мне дать вам краткое руководство по использованию let
s в RSpec.
Основное значение при использовании let
не зависит от экономии вычислительной мощности.Это неотъемлемая часть более широкой философии RSpec.Я постараюсь объяснить, и, надеюсь, вам будет легче прогрессировать ...
let
лениво
все, что вы определите внутри блока, будет вызываться тогда и только тогда, когдана самом деле он используется в спецификации:
context do
let(:foo) { sleep(10000) } # will not happen
specify { expect(1).to eq(1) }
end
context do
specify do
foo = sleep(10000) # you'll wait
expect(1).to eq(1)
end
end
Использование let!
, что является нетерпеливой (то есть не ленивой) версией let
let
запоминается
Все, что определено внутри блока, произойдет только один раз (в контексте контекста):
context do
let(:random_number) { rand }
specify do
expect(random_number).to eq(random_number) # will always pass
end
end
Если вы не хотите эту функцию, определите метод:
context do
def random_number
rand
end
specify do
expect(random_number).to eq(random_number) # sometimes pass, mostly fail
end
end
let
в контекстах более низкого уровня перезаписывает let
определения более высокого уровня:
context do
let(:x) { 1 }
specify { expect(x).to eq(1) # pass
context 'with different x' do
let(:x) { 2 }
specify { expect(x).to eq(2) # pass
end
context do
specify { expect(x).to eq(1) # pass
end
end
^ это позволяет вам составлять спецификации таким образом, где упоминаются только соответствующие «части» установкив контексте, например:
context do
let(:x) { 1 }
let(:y) { 1 }
let(:z) { 1 }
specify { expect(foo(x, y, z)).to eq(3) }
context 'when z is nil'
let(:z) { nil }
specify { expect(foo(x, y, z)).to raise_error) } # foo doesn't work with z = nil
end
context 'when x is nil'
let(:x) { nil }
specify { expect(foo(x, y, z)).to eq(15) }
end
end
Бонус: subject
это магия let
# writing
subject { foo(x) }
# is almost the same as writing
let(:subject) { foo(x) }
subject
является зарезервированным понятием в RSpec, это "вещь"вы тестируете ", чтобы вы могли написать пример с помощью` foo (x, y, z) следующим образом:
context do
let(:x) { 1 }
let(:y) { 1 }
let(:z) { 1 }
subject { foo(x, y, z) }
specify { expect(subject).to eq(3) }
context 'when z is nil'
let(:z) { nil }
specify { expect(subject).to raise_error) } # foo doesn't work with z = nil
end
context 'when x is nil'
let(:x) { nil }
specify { expect(foo(subject)).to eq(15) }
end
end
Относительно вашей ошибки ...
* 1044Объявления *
let
и subject
не предназначены для вызова в хуке before(:context)
, поскольку они существуют для определения состояния, которое сбрасывается между каждым примером, в то время как before(:context)
существует для
определения состояния, котороеявляется общим для примеров в группе примеров.
вы делаете что-то вроде
before do
let(:x) { ... }
end
просто не делайте этого, вы определяете let
внутри describe
иcontext
, но вы можете использовать их (не определять их, использовать то, что определено) внутри before
и specify
:
let(:name) { 'Frank' }
before do
User.create name: name
end
specify do
expect(User.where(name: name).count).to eq(1)
end