在 RSpec 测试中,"let"真正节省了多少时间?



我发现在代码中设置变量比使用let容易得多。let很挑剔,总是告诉我使用错误的方法。

当我在我的规范中使用一个简单的变量声明时,比如

tx_good = makeTransaction1(),一切正常。

但当我像一样使用let

let(:tx_good) { makeTransaction1() }我总是会遇到这样的错误,告诉我它不能在这里或那里。。。

`let` and `subject` declarations are not intended to be called
in a `before(:context)` hook, as they exist to define state that
is reset between each example, while `before(:context)` exists to
define state that is shared across examples in an example group.

考虑到使用let是多么挑剔,我不得不想,它是否值得我为使用它付出额外的努力和小心。有人知道使用let与仅仅预先分配变量相比,真正节省了多少处理时间吗?

我想遵循良好的测试协议,所以我希望有人能说服我为什么应该像其他人一样使用let

你用错了这些东西,我理解你的沮丧。因此,让我为您提供一份在RSpec中使用lets的简明手册。

使用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

关于你的错误

letsubject声明不打算在中调用before(:context)挂钩,因为它们的存在定义了在每个示例之间重置,而before(:context)的存在是为了
定义在示例组中的示例之间共享的状态。

你正在做类似的事情

before do
let(:x) { ... }
end

只是不要这样做,你在describecontext中定义了let,但你可以在beforespecify:中使用它们(不定义它们,使用定义的内容)

let(:name) { 'Frank' }
before do
User.create name: name
end
specify do
expect(User.where(name: name).count).to eq(1)
end

最新更新