什麼時候使用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()爲您提供了一種以「級聯」樣式定義一組變量的好方法。 經過這樣作,經過簡化代碼,規範看起來更好一些。

相關文章
相關標籤/搜索