Ruby 轨道-RSpec-之间的差异;让我们;及;让我来&引用;
我已经读到了关于差异的说法,但有些事情仍然令人困惑。所有其他来源,包括“RSpec手册”只解释了“let”和“Rails 3-Way”,与手册一样令人困惑 我知道“let”只有在被调用时才被计算,并且在一个范围内保持相同的值。因此,在本例的第一个示例中,第一个测试作为“let”仅调用一次而通过,第二个测试作为它添加到第一个测试的值(第一个测试中评估了一次,值为1)而通过是有意义的 接下来,由于“let!”在定义时进行计算,在调用时再次进行计算,那么测试是否应该失败为“count.should eq(1)”而不是“count.should eq(2)”Ruby 轨道-RSpec-之间的差异;让我们;及;让我来&引用;,ruby,rspec,rspec2,Ruby,Rspec,Rspec2,我已经读到了关于差异的说法,但有些事情仍然令人困惑。所有其他来源,包括“RSpec手册”只解释了“let”和“Rails 3-Way”,与手册一样令人困惑 我知道“let”只有在被调用时才被计算,并且在一个范围内保持相同的值。因此,在本例的第一个示例中,第一个测试作为“let”仅调用一次而通过,第二个测试作为它添加到第一个测试的值(第一个测试中评估了一次,值为1)而通过是有意义的 接下来,由于“let!”在定义时进行计算,在调用时再次进行计算,那么测试是否应该失败为“count.should e
任何帮助都将不胜感激。您可以阅读更多关于这方面的内容,但基本上是这样<代码>(:let)是延迟计算的,如果您不调用它,它将永远不会被实例化,而
(:let!)
是在每次方法调用之前被强制计算的。它在定义时不会被调用,而是在每个示例之前被调用(然后它被记住,并且不会被示例再次调用)。这样,count的值将为1
无论如何,如果您有另一个示例,则再次调用before钩子-以下所有测试都通过:
$count = 0
describe "let!" do
invocation_order = []
let!(:count) do
invocation_order << :let!
$count += 1
end
it "calls the helper method in a before hook" do
invocation_order << :example
invocation_order.should == [:let!, :example]
count.should eq(1)
end
it "calls the helper method again" do
count.should eq(2)
end
end
$count=0
描述“让我做!”
调用顺序=[]
让我来!(:count)做什么
调用顺序我也被let
和let搞糊涂了代码>,因此我从中获取了文档代码并使用它:
希望有帮助 我也认为这令人困惑,但我认为Rails 3-Way的例子很好。
let类似于before块中的实例变量,而let!立即记录
从轨道3路
describe BlogPost do
let(:blog_post) { BlogPost.create :title => 'Hello' }
let!(:comment) { blog_post.comments.create :text => 'first post' }
describe "#comment" do
before do
blog_post.comment("finally got a first post")
end
it "adds the comment" do
blog_post.comments.count.should == 2
end
end
end
“因为注释块永远不会在第一次执行
断言如果使用let定义,则只有一条注释
即使实现可能正在运行,也已添加到此规范中。
通过使用let!我们确保创建了初始注释,并且规范
现在将过去。”
我理解了let
和let之间的区别代码>使用一个非常简单的示例。让我先读一下doc语句,然后亲自展示输出
医生说:-
let
是惰性求值的:直到第一次才求值
调用它定义的方法
我通过下面的例子理解了区别:-
$count = 0
describe "let" do
let(:count) { $count += 1 }
it "returns 1" do
expect($count).to eq(1)
end
end
让我们现在运行它:-
arup@linux-wzza:~/Ruby> rspec spec/test_spec.rb
F
Failures:
1) let is not cached across examples
Failure/Error: expect($count).to eq(1)
expected: 1
got: 0
(compared using ==)
# ./spec/test_spec.rb:8:in `block (2 levels) in <top (required)>'
Finished in 0.00138 seconds (files took 0.13618 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/test_spec.rb:7 # let is not cached across examples
arup@linux-wzza:~/Ruby>
让我们运行以下代码:-
arup@linux-wzza:~/Ruby> rspec spec/test_spec.rb
.
Finished in 0.00145 seconds (files took 0.13458 seconds to load)
1 example, 0 failures
请参阅,现在$count
返回1
,因此测试通过。它发生在我使用let时代码>,它在示例运行之前运行,尽管我们没有在示例中调用count
这就是let
和let代码>彼此不同。这里有一种方法可以让您的规格保持可预测性
你应该经常使用let
。您不应该使用let代码>除非您有意要跨示例缓存该值。这就是为什么:
describe '#method' do
# this user persists in the db across all sub contexts
let!(:user) { create :user }
context 'scenario 1' do
context 'sub scenario' do
# ...
# 1000 lines long
# ...
end
context 'sub scenario' do
# you need to test user with a certain trait
# and you forgot someone else (or yourself) already has a user created
# with `let!` all the way on the top
let(:user) { create :user, :trait }
it 'fails even though you think it should pass' do
# this might not be the best example but I found this pattern
# pretty common in different code bases
# And your spec failed, and you scratch your head until you realize
# there are more users in the db than you like
# and you are just testing against a wrong user
expect(User.first.trait).to eq xxx
end
end
end
end
谢谢你,贾斯汀。那是我链接到的我不理解的“手册”。我的问题更多地集中在为什么链接中的“第二个规范”以“count.should eq(1)”而不是我预期的“count.should eq(2)”。如果在方法调用之前进行评估,并且在调用“count.should”时再次进行评估,那么第二个示例不应该等于2而不是1吗?halle flippin lujah,最后给出了一个解释,该解释没有涉及到记忆或是什么。简单而中肯,一切都应该如此。同意,这就是为什么第一个规范是有意义的。当然,第二个规范将在示例之前进行评估(使其等于1),然后在调用“count.should”(使其等于2)时再次进行评估?不,它已被调用和记忆,因此$count不会再次增加。无论如何,如果您有另一个示例,那么将再次调用before钩子。看到我编辑过的答案,我添加了一些代码来澄清。这意味着如果你使用“let”和一个spec(一个“it”)不doa“count.should”(或类似),那么增量就不会发生了?如果是这样,那么“let”就不应该被视为“before”,因为before默认意味着“let!”的功能。还是我又错过了什么?是记忆,不是记忆。从Obie Fernandez的书中可以看出,“memonized意味着与let相关联的代码块执行一次并存储起来以备将来调用,从而提高性能。”复制doc示例代码首先是问题的一部分。因此这里没有太大帮助。请记住,永远不要在块内有一个let块,这就是let块!这是为你而做的。有关更多信息,请查看此页面:
describe '#method' do
# this user persists in the db across all sub contexts
let!(:user) { create :user }
context 'scenario 1' do
context 'sub scenario' do
# ...
# 1000 lines long
# ...
end
context 'sub scenario' do
# you need to test user with a certain trait
# and you forgot someone else (or yourself) already has a user created
# with `let!` all the way on the top
let(:user) { create :user, :trait }
it 'fails even though you think it should pass' do
# this might not be the best example but I found this pattern
# pretty common in different code bases
# And your spec failed, and you scratch your head until you realize
# there are more users in the db than you like
# and you are just testing against a wrong user
expect(User.first.trait).to eq xxx
end
end
end
end