RSpec中letbefore块的区别是什么?

什么时候使用?

在下面的例子中,什么是好方法(let或before)?

let(:user) { User.make !}
let(:account) {user.account.make!}

before(:each) do
 @user = User.make!
 @account = @user.account.make!
end

我研究了这个stackoverflow post

但是,像上面这样为关联定义let好吗?

推荐答案

人们似乎已经解释了它们之间的一些基本差异,但遗漏了before(:all)个,并且没有确切解释为什么应该使用它们.

我认为实例变量在绝大多数规范中都没有使用的位置,部分原因是this answer中提到的原因,所以我在这里不提它们.

let blocks

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个块.这有助于设置用于大多数规格的默认值,如果需要,可以覆盖这些默认值.

例如,如果通过person模型并将top_hat设置为true,则判断返回值calculate_awesome,但没有胡子:

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个街区.

Also, never ever use before to trigger execution of let blocks, this is what let! is made for!

let! blocks

按照定义的顺序执行let!个块(很像before块).与before块的一个核心区别是,您得到了对这个变量的显式引用,而不需要返回到实例变量.

let个块一样,如果用相同的名称定义了多个let!个块,则执行中将使用最新的块.核心区别在于,如果像这样使用,let!个块将执行多次,而let个块将只执行最后一次.

before(:each) blocks

before(:each)是默认的before块,因此可以引用为before {},而不是每次指定完整的before(:each) {}.

我个人倾向于在一些核心情况下使用before个街区.如果出现以下情况,我将使用before blocks:

  • 我用的是嘲弄、存根或替身
  • 有任何合理大小的设置(通常这表明您的工厂没有正确设置)
  • 有许多变量我不需要直接引用,但它们是设置所必需的
  • 我正在rails中编写功能控制器测试,我想执行一个特定的测试请求(即before { get :index }).尽管在很多情况下你可以使用subject,但如果你不需要参考资料,它有时会让你感觉更明确.

如果你发现自己为你的规格写了before个大模块,判断你的工厂,确保你完全理解这些特性及其灵活性.

before(:all) blocks

在当前上下文(及其子上下文)中的规范之前,这些操作只执行一次.如果写得正确,这些可以发挥巨大的优势,因为在某些情况下,这可以减少执行和工作量.

一个例子(几乎不会影响执行时间)是为测试模拟一个ENV变量,您应该只需要做一次.

希望有帮助:)

Ruby-on-rails相关问答推荐

如何在嵌套路由中使用Ruby on rails多态关联

无法在 Rails 中使用 wkhtmltopdf 写入临时文件

Ruby/Rails 相当于 Python 的 sys.addAuditHook

使用带有 Paper Trail gem 的子类

如何使用 activerecord activerecord-session_store 在 Rails 应用程序中使用 cookie 值在数据库中查找会话记录

Rails - 按连接表数据排序

attr_accessible(*attributes) 和 attr_protected(*attributes) 有什么区别?

循环大量记录时 Ruby on Rails 内存泄漏; find_each 没有帮助

使用 RSpec 和 Capybara (Rails) 测试重定向

Rails 3.1 Sprockets 需要指令 - 有没有办法排除特定文件?

form_for 未定义的方法 `user_path'

如何在 Rails 迁移中添加一些插入?

Heroku Postgres 错误:PGError:错误:关系组织不存在(ActiveRecord::StatementInvalid)

Rspec:如何在控制器规范中分配实例变量

通过get in rails传递参数数组

ActiveRecord 查找以

让 bundler 为不同的平台使用不同的 gem

在 Rails 3 中设置会话超时

Rails - 邮件,将正文作为纯文本获取

如何在 Rails 表单中将复选框和标签保持在同一行?