如何在Rails 3.1可安装引擎中测试路由

时间:2011-10-07 18:48:20

标签: ruby-on-rails ruby-on-rails-3 rspec2

我正在尝试为可安装的rails 3.1引擎编写一些路由规范。我有工作模型和控制器规格,但我无法弄清楚如何指定路线。

对于示例引擎'testy',我尝试的每种方法都以相同的错误结束:

 ActionController::RoutingError:
   No route matches "/testy"

我已经尝试了Rspec和Test :: Unit语法(spec / routing / index_routing_spec.rb):

describe "test controller routing" do
  it "Routs the root to the test controller's index action" do
    { :get => '/testy/' }.should route_to(:controller => 'test', :action => 'index')
  end

  it "tries the same thing using Test::Unit syntax" do
    assert_routing({:method => :get, :path => '/testy/', :use_route => :testy}, {:controller => 'test', :action => 'index'})
  end
end

我已正确布局路线(config / routes.rb):

Testy::Engine.routes.draw do
  root :to => 'test#index'
end

并将它们安装在虚拟应用程序中(spec / dummy / config / routes.rb):

Rails.application.routes.draw do
  mount Testy::Engine => "/testy"
end

运行rails server并请求http://localhost:3000/testy/就可以了。

我是否遗漏了任何明显的东西,或者这只是没有适当地融入框架呢?

更新:正如@andrerobot指出的那样,rspec人员已经在2.14版本中解决了这个问题,所以我已经相应地更改了我接受的答案。

6 个答案:

答案 0 :(得分:12)

自RSpec 2.14起,您可以使用以下内容:

describe "test controller routing" do
  routes { Testy::Engine.routes }
  # ...
end

来源:https://github.com/rspec/rspec-rails/pull/668

答案 1 :(得分:11)

尝试使用以下内容添加前一个块:

before(:each) { @routes = Testy::Engine.routes }

这对我有用,因为路由规范使用该顶级实例变量来测试其路由。

答案 2 :(得分:11)

史蒂芬安德森的回答让我大部分都在那里,但需要相对于引擎而不是应用程序提出请求 - 可能是因为这种技术用引擎的路线取代了应用程序的路线,所以现在一切都是相对于发动机。这对我来说似乎有点脆弱,但我还没有看到另一种有效的方式。如果有人发布了更清洁的方式,我会很乐意接受这个答案。

在'dummy'应用程序中,如果引擎安装如下(spec / dummy / config / routes.rb):

Rails.application.routes.draw do
  mount Testy::Engine => "/testy"
end

以下规范将使用rspec和test :: unit语法(spec / routing / index_route_spec.rb)正确测试引擎的根路由:

require 'spec_helper'

describe "test controller routing" do
  before(:each) { @routes = Testy::Engine.routes }

  it "Routes the root to the test controller's index action" do
    { :get => '/' }.should route_to(:controller => 'testy/test', :action => 'index')
  end

  it "tries the same thing using Test::Unit syntax" do
    assert_routing({:method => :get, :path => '/'}, {:controller => 'testy/test', :action => 'index'})
  end
end

答案 3 :(得分:4)

这对我有用:

# spec_helper.rb
RSpec.configure do |config|
  config.include MyEngine::Engine.routes.url_helpers
end

答案 4 :(得分:1)

对我来说,这是迄今为止所有参与者的评论组合。

首先,我从这个简单的测试开始:

  it "routes / to the widgets controller" do
    get('/').should route_to("mozoo/widget#index")
  end

这导致:

Failures:
  1) Mozoo::WidgetController GET widget index routes / to the widgets controller
     Failure/Error: get('/').should route_to("mozoo/widget#index")
     ActionController::RoutingError:
       No route matches {:controller=>"mozoo/widget", :action=>"/"}
     # ./spec/controllers/mozoo/widget_controller_spec.rb:9:in `block (3 levels) in <module:Mozoo>'

所以我从get('/')切换到{ :get => '/' },事情开始变得很好。不知道为什么。根据{{​​3}},没有区别,但它对我有所影响。无论如何,谢谢@ cameron-pope。

接下来,我添加了另一个非常简单且非常相似的测试:

it "routes root_path to the widgets controller" do
  { :get => root_path }.should route_to("mozoo/widget#index")
end

并且收到了这个错误:

Failures:
  1) Mozoo::WidgetController GET widget index routes root_path to the widgets controller
     Failure/Error: { :get => '/mozoo' }.should route_to("mozoo/widget#index")
       No route matches "/mozoo"
     # ./spec/controllers/mozoo/widget_controller_spec.rb:14:in `block (3 levels) in <module:Mozoo>'

所以我补充说:

before(:each) { @routes = Mozoo::Engine.routes }

得到了更好/不同的错误:

Failures:
  1) Mozoo::WidgetController GET widget index routes root_path to the widgets controller
     Failure/Error: { :get => root_path }.should route_to("mozoo/widget#index")
       The recognized options <{"controller"=>"mozoo/widget", "action"=>"index", "section"=>"mozoo"}> did not match <{"controller"=>"mozoo/widget", "action"=>"index"}>, difference: <{"section"=>"mozoo"}>.
       <{"controller"=>"mozoo/widget", "action"=>"index"}> expected but was
       <{"controller"=>"mozoo/widget", "action"=>"index", "section"=>"mozoo"}>.
     # ./spec/controllers/mozoo/widget_controller_spec.rb:14:in `block (3 levels) in <module:Mozoo>'

从那里,我改变了我的测试以包括该部分(我的引擎所在的命名空间):

{ :get => root_path }.should route_to(:controller => "mozoo/widget", :action => "index", :section => "mozoo")

中提琴,它过去了。谢谢@ steven-anderson。

下一部分很奇怪。为特定小部件添加另一个测试后,该小部件使用widget_path url helper作为命名路由:

  it "will successfully serve the widget show page" do
    visit widget_path(:foobar)
    response.should be_success
  end

测试迅速炸毁了我:

Failures:
  1) GET bubble_summary_row widget will have the content section properly scoped
     Failure/Error: visit widget_path(:bubble_summary_row)
     NoMethodError:
       undefined method `widget_path' for #<RSpec::Core::ExampleGroup::Nested_3:0x0000010748f618>
     # ./spec/views/mozoo/widgets/show.html.haml_spec.rb:7:in `block (2 levels) in <module:Mozoo>'

所以我添加了以下spec_helper配置条目:

RSpec.configure do |config|
  config.include Testy::Engine.routes.url_helpers
end

和BAM!它过去了。谢谢@sam-soffes。使这个奇怪的是,稍后在创建此注释时,我删除了该配置条目以尝试将错误恢复,我无法通过删除配置条目来重现错误。哦,我继续前进。希望这个冗长的帐户有助于某人。

答案 5 :(得分:1)

基于this回答,我选择了以下解决方案:

#spec/spec_helper.rb
RSpec.configure do |config|
 # other code
 config.before(:each) { @routes = MyEngine::Engine.routes }
end

附加好处是,您不需要在每个控制器规范中都有before(:each)块。