我傾向於在塊以前使用來設置實例變量。 而後,我在個人示例中使用這些變量。 我最近遇到了let()
。 根據RSpec文檔,它習慣了 數據庫
...定義一個memoized幫助方法。 該值將在同一示例中的多個調用之間緩存,但不跨示例緩存。 api
這與在塊以前使用實例變量有什麼不一樣? 還有何時你應該使用let()
vs before()
? 緩存
默認狀況下,「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
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}
約瑟夫的注意事項 - 若是您在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
我使用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
這使規格清晰可讀。
使用實例變量和let()
之間的區別在於let()
是惰性求值的 。 這意味着在第一次運行它定義的方法以前,不會評估let()
。
before
和let
之間的區別在於let()
爲您提供了一種以「級聯」樣式定義一組變量的好方法。 經過這樣作,經過簡化代碼,規範看起來更好一些。