2011-10-06 69 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 

希望它帮助,并再次谨慎使用