使用RSpec 2测试Rail的路由约束lambda

3

问题:

如何设置/模拟rspec路由测试,使其更像生产环境的rack环境?

如果能够首先调用控制器的身份验证函数(例如ApplicationController.authenticate_user)来设置session[:current_user_id],则会获得额外的奖励分数。

详情:

我正在使用route :constraints将www.example.com/路由到两个不同的控制器和视图,具体取决于用户是否已登录。

root :to => 'intentions#latest', :constraints => lambda {|r| r.env['rack.session'].has_key?(:current_user_id) }
root :to => 'welcome#index'

我想确保这个易碎的路由有一个适当的测试。虽然cukes正在测试它,但我想进行更深入的测试,特别是当我弄错了:current_user_id时,cukes没有捕获到。例如,在我的ApplicationController的authenticate_user()方法中,我误输入了:current_user_id。很想在before(:each)中调用它,并确保我设置了正确的会话密钥。
因此,我创建了一个名为/spec/routing/auth_routing_spec.rb的文件,并尝试遵循http://relishapp.com/rspec/rspec-rails/v/2-6-rc/dir/routing-specs上的指南。我创建了以下规范:
it "/ should send me to home page" do
  get('/').should route_to(:controller => :index)
end

当我运行规范时,在具有 :constraint 的路由上遇到了这个错误。我认为 env['rack.session'] 不存在。我尝试通过 Rails.application.call(Rack::MockRequest.env_for('/')) 模拟请求对象,但没有帮助。
Failure/Error: get('/').should route_to(:controller => :index)
NoMethodError:
  undefined method `has_key?' for nil:NilClass


无聊的应用细节

rake about 会返回以下内容:

Ruby version              1.9.2 (x86_64-darwin10.6.0)
RubyGems version          1.6.2
Rack version              1.2
Rails version             3.0.7
Active Record version     3.0.7
Action Pack version       3.0.7
Active Resource version   3.0.7
Action Mailer version     3.0.7
Active Support version    3.0.7

grep rspec gemfile.info 的结果如下:

remote: git://github.com/rspec/rspec-rails.git
  rspec-rails (2.6.0.rc6)
    rspec (= 2.6.0.rc6)
  rspec (2.6.0.rc6)
    rspec-core (= 2.6.0.rc6)
    rspec-expectations (= 2.6.0.rc6)
    rspec-mocks (= 2.6.0.rc6)
  rspec-core (2.6.0.rc6)
  rspec-expectations (2.6.0.rc6)
  rspec-mocks (2.6.0.rc6)
rspec-rails!

你尝试过在方法链中的某个地方创建一个env方法吗?例如,找到一个可能是路由类的父类来依附,然后依附到那个类上。这比试图将rack插入不使用它的测试集中要容易得多。例如:AppName :: Application.stub(:env).and_return(double(:x => y))等等。 - stuartc
1个回答

1

我在我的控制器规范中做了类似的事情,也许这种方法在这里也适用?

describe "some controller" do
  it "does something" do
    request.stub(:env => {'rack.session' => {'current_user' => '42'})
    get :my_action
    response.should be_cool
  end
end

经过反思,对于您来说更好的方法可能是:

class CurrentUserConstraint
  def self.matches?(request)
    request.session[:current_user_id].present?
  end
end

并且:

root :to => 'intentions#latest', :constraints => CurrentUserConstraint.new

然后你可以将逻辑放在一个易于测试的类中。


我认为两者的结合非常棒。将约束作为自己的对象进行测试非常好。通过存根会话也能够测试路由,这是一个额外的奖励。我会在这个周末尝试一下。 - Peter Baker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接