“需要多少时间?”;让我们;在RSpec测试中真的节省了吗?
我发现在代码中设置变量比使用“需要多少时间?”;让我们;在RSpec测试中真的节省了吗?,rspec,performance-testing,rspec-rails,let,Rspec,Performance Testing,Rspec Rails,Let,我发现在代码中设置变量比使用let容易得多let很挑剔,总是告诉我错误使用它的方式 当我在我的规范中使用一个简单的变量声明时,比如 tx\u good=makeTransaction1(),一切正常 但是当我使用时,就让像这样 让(:tx_good){makeTransaction1()}我总是会遇到这样的错误,告诉我它不能在这里或那里运行 `let` and `subject` declarations are not intended to be called in a `befo
let
容易得多let
很挑剔,总是告诉我错误使用它的方式
当我在我的规范中使用一个简单的变量声明时,比如
tx\u good=makeTransaction1()
,一切正常
但是当我使用时,就让像这样
让(: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中使用let
s的简明手册
使用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
让
被记忆
在块内定义的内容只会发生一次(在上下文范围内):
如果不需要此功能,请定义一种方法:
context do
def random_number
rand
end
specify do
expect(random_number).to eq(random_number) # sometimes pass, mostly fail
end
end
let
在较低级别的上下文中覆盖较高级别的定义:
^这允许您以一种只在上下文中提及设置的相关“部分”的方式来编写规范,例如:
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
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
关于你的错误。。。
让
和主题
声明不被调用
(:context)
之前的钩子,因为它们的存在定义了
在每个示例之间重置,而(:context)
之前的存在于
定义示例组中跨示例共享的状态
你在做类似的事情
before do
let(:x) { ... }
end
不要这样做,你可以在中定义让描述和上下文,但你可以在中使用它们(不定义它们,使用定义的内容),然后在和中指定:
let(:name) { 'Frank' }
before do
User.create name: name
end
specify do
expect(User.where(name: name).count).to eq(1)
end
让我们给出一种共享代码和依赖项的方法,这些代码和依赖项是惰性的,并且是线程安全的。从你的例子来看,你没有正确地使用它们,所以在你放弃它们之前,我会先试用一下。第二@Anthony我同样对let
感到失望,很久以前,这有点让人困惑,因为你似乎在测试之外声明变量。您可以将let
放在description
或context
块中,但不能放在it
或块之前的中。基本上,这会创建一个可重用的变量,为每个测试创建一个新的变量,这有助于防止测试之间的数据库工件,并具有延迟加载的额外好处,延迟加载只在调用变量后创建该变量。这可能会造成表面上的“挑剔”行为,但实际上是在做它应该做的事。:)经过深思熟虑的解释应该被接受,因此let
对于设置不同的场景进行测试非常有用,而不会以可能破坏其他测试的方式更改共享变量的状态。有点像把一个变量传递给一个小函数,然后创建它自己的作用域。它似乎也减少了对新变量名的需求,因为我们可以在不同的上下文中重用相同的符号。还请注意,单行语法允许您将“expect(subject)”替换为“is_expected”或替换为“expect(subject)”。to“to”替换为“should”,例如subject{3};它{应为等式(3)};它{被期望为等式(3)}
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
before do
let(:x) { ... }
end
let(:name) { 'Frank' }
before do
User.create name: name
end
specify do
expect(User.where(name: name).count).to eq(1)
end