2011-10-06 63 views
11

我有一個簡單的控制器測試,包含a.o.下面的代碼:加速rspec控制器測試:使用之前全部失敗?

context "POST :create" do 
    before (:each) do 
    post :create, :user_id => @user.id, 
     :account => { .. some data ... } 
    end 
    it { response.status.should == 201 } 
    it { response.location.should be_present } 
end 

現在我想到了一個非常簡單的方法來加快這一測試,並使用before(:all)代替before(:each)的。在這種情況下,該帖子只能進行一次。

所以我寫了:

context "POST :create" do 
    before (:all) do 
    post :create, :user_id => @user.id, 
     :account => { .. some data ... } 
    end 
    it { response.status.should == 201 } 
    it { response.location.should be_present } 
end 

但後來我得到以下錯誤:

RuntimeError: 
    @routes is nil: make sure you set it in your test's setup method. 

這是設計?有沒有辦法避開它?

+1

您是否找到了解決方案?我遇到了同樣的問題。 – ktusznio

回答

12

我問RSpec的郵件列表上的這個問題,並得到了來自@dchelimsky自己的以下回復:

是的。 rspec-rails包裝了rails的測試框架,它沒有之前的(:all)概念,所以所有的數據都在每個示例之前重置。即使我們想在rspec-rails(我不這樣做)中支持它,它需要首先對rails進行更改。

因此,在before(:all)中不可能進行控制器調用,它只能用於設置DB或實例變量。

2

我不知道這是否是一個好主意,但在before(:each)塊設置與||=類變量似乎工作:

describe PagesController do 
    describe "GET 'index'" do 
    before(:each) do 
     @@response ||= begin 
     get :index 
     response 
     end 
    end 
    it { @@response.should redirect_to(root_path) } 
    it { @@response.status.should == 301 } 
    it { @@response.location.should be_present } 
    end 
end 
+0

你試過這個嗎?當我測試這個時,POST甚至沒有工作,因爲你還沒有在任何控制器上下文中。 – nathanvda

+0

糟糕,這是爲了說_haven't_試過這個。用不同的技術更新答案。 – Zubin

+0

現在你再次做一個'before(:each)',這正是我想要避免的,然後有更漂亮/可讀的方法來寫它。如果你在'之前:每個'你都可以寫'get:index'並使用'response'。 – nathanvda

3

如果你想走髒兮兮的全球變量的道路,並從超速增加中受益,可以使用小心。這種凌亂的邏輯完成了這項工作,但卻以明顯可讀的測試破壞了駕駛的目的。在幫助中重構產量比建議更重要。

describe PagesController do 
    describe "GET 'index'" do 
    before(:each) do 
     GLOBAL ||= {} 
     @response = GLOBAL[Time.now.to_f] || begin 
     get :index 
     response 
     end 
    end 
    it { @response.should redirect_to(root_path) } 
    it { @response.status.should == 301 } 
    it { @response.location.should be_present } 
    end 
end 

,你可以把你的選擇,在規範的文件中的重構/支持一切爲遵循

RSPEC_GLOBAL = {} 

def remember_through_each_test_of_current_scope(variable_name) 
    self.instance_variable_set("@#{variable_name}", RSPEC_GLOBAL[variable_name] || begin 
    yield 
    end) 
    RSPEC_GLOBAL[variable_name] ||= self.instance_variable_get("@#{variable_name}") 
end 

因此,在測試文件中的代碼就變成了:

describe PagesController do 
    describe "GET 'index'" do 
    before(:each) do 
     remember_through_each_test_of_current_scope('memoized_response') do 
     get :index 
     response 
     end 
    end 
    it { @memoized_response.should redirect_to(root_path) } 
    it { @memoized_response.status.should == 301 } 
    it { @memoized_response.location.should be_present } 
    end 
end 

希望它幫助,並再次謹慎使用