在RSpec中,有两种不同的编写DRY测试的方法,即使用before或let 。 它们的目的是创建在测试之间通用的变量。 在本文中,我们将探讨before和let之间的区别,并解释为什么Ruby社区更喜欢let 。
让
让我们创建延迟评估的局部变量。 这意味着在首次运行let()定义的方法之前,不会对其进行评估。 它使规范变干并使其更具可读性。
$count = 0
describe "let" do
let( :count ) { $count += 1 }
it "stores the value" do
expect(count).to eq( 1 )
expect(count).to eq( 1 )
end
it "is not cached across examples" do
expect(count).to eq( 2 )
end
end
let不应用于必须保存到数据库的局部变量,因为除非已被引用,否则它们不会保存到数据库。 在这种情况下,您应该使用let! 或在块之前 。
我们正在创建的测试是使用RSpec和Capybara完成的 。
另外, 永远不要在块之前的一个let块之内,这就是let! 是为!
让!
与let不同,您可以使用let! 强制在每个示例之前调用方法 。 这意味着,即使您没有在示例中调用辅助方法,该方法也将在示例运行之前被调用。
$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
expect(invocation_order).to eq([ :let! , :example ])
expect(count).to eq( 1 )
end
end
与let块一样,如果有多个let! 块以相同的名称定义,将执行最新的块。 核心区别在于让! 如果这样使用,则块将执行多次,而let块将仅执行最后一次。
之前(:每个)
即使示例未使用该块中定义的任何实例变量,before(:each)块也将在每个示例之前运行。 这会明显减慢实例变量的设置。
class User
def tests
@tests || = []
end
end
describe User do
before( :each ) do
@user = User.new
end
describe "initialized in before(:each)" do
it "has 0 tests" do
@user.should have( 0 ).tests
end
it "can accept new tests" do
@user.tests << Object.new
end
it "does not share state across examples" do
@user.should have( 0 ).tests
end
end
end
在几乎每种情况下,最好在块之前使用let。 根据您的个人喜好,您可以在以下情况下在块之前使用:
- 有一定数量的变量。
- 有些变量不需要直接引用而是必需的。
- 有许多命令要执行,因为当涉及到许多命令时,其语法更加清晰。
- 创建模拟/存根。
尝试一下,创建自己的模型或控制器测试 !
之前(:全部)
在组中的所有示例之前,该块仅执行一次。 在某些情况下,这会减少执行力和工作量。
class User
def tests
@tests || = []
end
end
describe User do
before( :all ) do
@user = User.new
end
describe "initialized in before(:all)" do
it "has 0 tests" do
@user.should have( 0 ).tests
end
it "can get accept new tests" do
@user.tests << Object.new
end
it "shares state across examples" do
@user.should have( 1 ).tests
end
end
end
除非您知道自己在做什么,否则在RSpec中使用before(:all)会给您带来很多麻烦! 它在事务之外运行,因此此处创建的数据将渗入其他规范。
结论
让块为表带来比之前更多的信息。 这完全取决于您需要什么以及如何使RSpec测试正常工作,或者考虑使用FactoryGirl创建数据。
除了速度较慢之外,before块的主要问题之一是拼写错误可能导致错误和误报,从而允许某些类型的测试在不应该通过的情况下通过。
before( :each ) do
@user = User.find( username: "kolosek" )
@user.logout
end
it "should log the user out" do
expect(@usr).to be_nil
end
由于先前未定义@usr,因此测试将通过,默认情况下@usr为nil。 使用let的相同测试会引发NameError,因为未定义@usr。
希望这将帮助您更好地了解let和before块之间的区别。
感谢您的阅读!
先前发布在https://kolosek.com/rspec-let-vs-before/
From: https://hackernoon.com/rspec-testing-let-vs-before-s2q83y16