什么时候使用RSpec let()?

我倾向于在块以前使用来设置实例变量。 而后,我在个人示例中使用这些变量。 我最近遇到了let() 。 根据RSpec文档,它习惯了 数据库

...定义一个memoized帮助方法。 该值将在同一示例中的多个调用之间缓存,但不跨示例缓存。 api

这与在块以前使用实例变量有什么不一样? 还有何时你应该使用let() vs before()缓存


#1楼

默认状况下,“before”表示before(:each) 。 Ref The Rspec Book,copyright 2010,page 228。 app

before(scope = :each, options={}, &block)

我使用before(:each)为每一个示例组播种一些数据,而没必要调用let方法在“it”块中建立数据。 在这种状况下,“it”块中的代码较少。 post

若是我想在某些示例中使用某些数据而不是其余示例,则使用let测试

以前和以前都很适合干掉“它”块。 spa

为避免混淆,“let”与before(:all) 。 “让”从新评估每一个示例(“it”)的方法和值,可是在同一个示例中将值缓存到多个调用中。 你能够在这里阅读更多相关信息: https//www.relishapp.com/rspec/rspec-core/v/2-6/docs/helper-methods/let-and-let code


#2楼

let是功能性的,由于它本质上是一个Proc。 也是它的缓存。 对象

我获得的一个问题是......在一个正在评估变化的Spec块中。 事务

let(:object) {FactoryGirl.create :object}

expect {
  post :destroy, id: review.id
}.to change(Object, :count).by(-1)

你须要必定要打电话let你想到块以外。 即你在let块中调用FactoryGirl.create 。 我一般经过验证对象是否持久来作到这一点。

object.persisted?.should eq true

不然,当第一次调用let块时,因为延迟实例化而实际发生数据库更改。

更新

只需添加备注。 当心打码高尔夫或在这种状况下rspec高尔夫与这个答案。

在这种状况下,我只须要调用一个对象响应的方法。 因此我调用_.persisted? _对象的方法做为它的真实。 我要作的就是实例化对象。 你能够打电话给空吗? 仍是没有? 太。 关键不在于测试,而是经过调用它来引导生命。

因此你没法重构

object.persisted?.should eq true

成为

object.should be_persisted

由于对象还没有实例化...它的懒惰。 :)

更新2

利用让! 即时对象建立的语法 ,应该彻底避免这个问题。 注意虽然它会战胜不少非撞击让懒惰的目的。

此外,在某些状况下,您可能实际上想要利用主题语法而不是let,由于它可能会为您提供其余选项。

subject(:object) {FactoryGirl.create :object}

#3楼

约瑟夫的注意事项 - 若是您在before(:all)建立数据库对象,它们将不会在事务中捕获,而且您更有可能在测试数据库中留下残余物。 使用before(:each)代替。

使用let及其懒惰评估的另外一个缘由是你能够经过覆盖上下文中的let来获取一个复杂的对象并测试单个部分,就像在这个很是人为的例子中同样:

context "foo" do
  let(:params) do
     { :foo => foo,  :bar => "bar" }
  end
  let(:foo) { "foo" }
  it "is set to foo" do
    params[:foo].should eq("foo")
  end
  context "when foo is bar" do
    let(:foo) { "bar" }
    # NOTE we didn't have to redefine params entirely!
    it "is set to bar" do
      params[:foo].should eq("bar")
    end
  end
end

#4楼

我使用let来使用上下文在个人API规范中测试个人HTTP 404响应。

要建立资源,我使用let! 。 可是为了存储资源标识符,我使用let 。 看看它的样子:

let!(:country)   { create(:country) }
let(:country_id) { country.id }
before           { get "api/countries/#{country_id}" }

it 'responds with HTTP 200' { should respond_with(200) }

context 'when the country does not exist' do
  let(:country_id) { -1 }
  it 'responds with HTTP 404' { should respond_with(404) }
end

这使规格清晰可读。


#5楼

使用实例变量和let()之间的区别在于let()惰性求值的 。 这意味着在第一次运行它定义的方法以前,不会评估let()

beforelet之间的区别在于let()为您提供了一种以“级联”样式定义一组变量的好方法。 经过这样作,经过简化代码,规范看起来更好一些。

相关文章
相关标签/搜索