let
和before
RSpec中的块有什么区别?
以及何时使用它们?
在下面的示例中,什么是更好的方法(之前或之后)?
let(:user) { User.make !}
let(:account) {user.account.make!}
before(:each) do
@user = User.make!
@account = @user.account.make!
end
我研究了这个stackoverflow帖子
但是像上面这样定义允许关联的东西好吗?
let
和before
RSpec中的块有什么区别?
以及何时使用它们?
在下面的示例中,什么是更好的方法(之前或之后)?
let(:user) { User.make !}
let(:account) {user.account.make!}
before(:each) do
@user = User.make!
@account = @user.account.make!
end
我研究了这个stackoverflow帖子
但是像上面这样定义允许关联的东西好吗?
Answers:
人们似乎已经解释了它们之间区别的一些基本方法,但被遗漏了,before(:all)
并且没有确切解释为什么应该使用它们。
我认为实例变量在绝大多数规范中都没有使用,部分原因是此答案中提到的原因,因此在这里我不会将它们作为选项。
让块
let
块中的代码仅在被引用时执行,延迟加载意味着这些块的顺序无关紧要。这为您提供了强大的功能,可减少您通过规格进行的重复设置。
这样的一个例子(极其小巧)是:
let(:person) { build(:person) }
subject(:result) { Library.calculate_awesome(person, has_moustache) }
context 'with a moustache' do
let(:has_moustache) { true }
its(:awesome?) { should be_true }
end
context 'without a moustache' do
let(:has_moustache) { false }
its(:awesome?) { should be_false }
end
您可以看到has_moustache
在每种情况下定义都不同,但是无需重复subject
定义。需要注意的重要一点是,let
将使用当前上下文中定义的最后一个块。这对于将默认设置用于大多数规格非常有用,如果需要,可以将其覆盖。
例如,检查calculate_awesome
if 的返回值是否传递了设置为true 的person
模型top_hat
,但没有胡须是:
context 'without a moustache but with a top hat' do
let(:has_moustache) { false }
let(:person) { build(:person, top_hat: true) }
its(:awesome?) { should be_true }
end
关于let块要注意的另一件事,如果您正在搜索已保存到数据库(例如Library.find_awesome_people(search_criteria)
)的东西,则不应使用它们,因为除非已被引用,否则它们不会被保存到数据库。let!
或before
块是这里应该使用的。
此外,从来没有过使用before
到的触发器执行let
块,这是let!
用于制造!
让!块
let!
块按照定义的顺序执行(很像before块)。与before块的一个核心区别是,您可以对此变量进行显式引用,而无需使用实例变量。
与let
块一样,如果let!
使用相同的名称定义了多个块,则最新的将用于执行。核心区别在于,let!
如果这样使用,则块将被执行多次,而该let
块将仅在最后一次执行。
before(:each)块
before(:each)
是默认的before块,因此可以被引用为before {}
而不是before(:each) {}
每次都指定完整的。
before
在一些核心情况下使用块是我个人的喜好。在以下情况下,我将使用before块:
before { get :index }
)。即使您可以subject
在许多情况下使用此功能,但如果您不需要参考,有时感觉也会更加明确。如果发现自己before
为规格写了大块代码,请检查您的工厂,并确保您完全了解特质及其灵活性。
before(:all)块
在当前上下文中的规范(及其子规范)之前,它们仅执行一次。如果编写得当,这些可以发挥很大的优势,因为在某些情况下,这样做可以减少执行和工作量。
一个示例(根本不会影响执行时间)是模拟一个ENV变量进行测试,您只需执行一次即可。
希望有帮助:)
before(:all)
选项在Minitest中不存在。这是评论中的一些解决方法:github.com/seattlerb/minitest/issues/61
its
不再位于rspec-core中。一种更现代,更惯用的方式是it { is_expected.to be_awesome }
。
未提及的最大区别是,使用定义的变量let
在您首次调用之前不会实例化。因此,尽管一个before(:each)
块可以实例化所有变量,但let
让我们定义可以在多个测试中使用的多个变量,但它不会自动实例化它们。如果您不希望知道这些,那么如果您希望所有数据都预先加载,那么您的测试可能会再次被您咬伤。在某些情况下,您甚至可能想要定义多个let
变量,然后使用一个before(:each)
块来调用每个let
实例,以确保可以从其开始使用数据。
let!
用来定义在每个示例之前调用的方法。参见RSpec文档。