简体   繁体   English

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

[英]How to test routes in a Rails 3.1 mountable engine

I am trying to write some routing specs for a mountable rails 3.1 engine. 我正在尝试为可安装的rails 3.1引擎编写一些路由规范。 I have working model and controller specs, but I cannot figure out how to specify routes. 我有工作模型和控制器规格,但我无法弄清楚如何指定路线。

For a sample engine, 'testy', every approach I try ends with the same error: 对于示例引擎'testy',我尝试的每种方法都以相同的错误结束:

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

I've tried both Rspec and Test::Unit syntax (spec/routing/index_routing_spec.rb): 我已经尝试了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

I've laid out the routes correctly (config/routes.rb): 我已经正确布局了路由(config / routes.rb):

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

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

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

And running rails server and requesting http://localhost:3000/testy/ works just fine. 并运行rails server并请求http://localhost:3000/testy/工作正常。

Am I missing anything obvious, or is this just not properly baked into the framework yet? 我错过了任何明显的东西,或者这只是没有适当地融入框架中了吗?

Update: As @andrerobot points out, the rspec folks have fixed this issue in version 2.14, so I've changed my accepted answer accordingly. 更新:正如@andrerobot指出的那样,rspec人员已经在2.14版本中解决了这个问题,所以我相应地改变了我接受的答案。

Since RSpec 2.14 you can use the following: 从RSpec 2.14开始,您可以使用以下内容:

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

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

Try adding a before block with the following: 尝试使用以下内容添加前块:

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

That worked for me, as the routing specs use that top level instance variable to test their routes. 这对我有用,因为路由规范使用顶级实例变量来测试他们的路由。

The answer from Steven Anderson got me most of the way there, but the requests need to be made relative to the engine, rather than the app - probably because this technique replaces the app's routes with the engine's routes, so everything is now relative to the engine. Steven Anderson的答案让我大部分都在那里,但需要相对于引擎而不是应用程序提出请求 - 可能是因为这种技术用引擎的路线替换了应用程序的路线,所以现在一切都相对于发动机。 It seems a little fragile to me, but I haven't seen another way that works. 这对我来说似乎有点脆弱,但我还没有看到另一种有效的方式。 If someone posts a cleaner way of doing this, I'll be happy to accept that answer instead. 如果有人发布了更清洁的方式,我会很乐意接受这个答案。

In the 'dummy' app, if the engine is mounted as follows (spec/dummy/config/routes.rb): 在'dummy'应用程序中,如果引擎安装如下(spec / dummy / config / routes.rb):

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

The following spec will correctly test the root route of the engine using both rspec and test::unit syntax (spec/routing/index_route_spec.rb): 以下规范将使用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

This worked for me: 这对我有用:

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

For me, it was a combination of comments by pretty much everybody involved so far. 对我来说,这是迄今为止所有参与者的评论组合。

First, I started with this simple test: 首先,我从这个简单的测试开始:

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

This resulted in: 这导致:

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>'

So I switched from get('/') to { :get => '/' } and things started working great. 所以我从get('/')切换到{ :get => '/' } ,事情开始变得很好。 Not sure why. 不知道为什么。 According to lib/rspec/rails/matchers/routing_matchers.rb L102-105 , there is no difference, but it makes a difference to me. 根据lib / rspec / rails / matchers / routing_matchers.rb L102-105 ,没有区别,但它对我有所影响。 Regardless, thanks @cameron-pope. 无论如何,谢谢@ cameron-pope。

Next, I added another pretty simple and very similar test as that above: 接下来,我添加了另一个非常简单且非常相似的测试,如上所述:

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

And was getting this error: 并得到这个错误:

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>'

So I added this: 所以我补充说:

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

And got a better/different error: 并得到一个更好/不同的错误:

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>'

From there, I changed my test to include the section (the namespace my engine is under): 从那里,我改变了我的测试以包括该部分(我的引擎所在的命名空间):

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

And viola, it passed. 而中提琴,它通过了。 Thanks @steven-anderson. 谢谢@史蒂文安德森。

This next part is odd. 下一部分很奇怪。 After adding another test for a specific widget which used the widget_path url helper for a named route: 为特定小部件添加另一个测试后,该小部件使用widget_path url helper作为命名路由:

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

The test promptly blowd up on me with: 测试迅速炸毁了我:

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>'

So I added the following spec_helper config entry: 所以我添加了以下spec_helper配置条目:

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

And BAM! 和BAM! It passed. 它过去了。 Thanks @sam-soffes. 谢谢@sam-soffes。 What makes this odd is that later on when creating this comment, I removed that config entry to try and get the error back and I was unable to reproduce the error simply by removing the config entry. 使这个奇怪的是,稍后在创建此注释时,我删除了该配置条目以尝试并返回错误,我无法仅通过删除配置条目来重现错误。 Oh well, I'm moving on. 哦,我继续前进。 Hopefully this long-winded account helps somebody. 希望这个冗长的帐户可以帮助某人。

Based on this answer I chose the following solution: 根据这个答案,我选择了以下解决方案:

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

The additional benefit is, that you don't need to have the before(:each) block in every controller-spec. 额外的好处是,您不需要在每个控制器规范中都有before(:each)块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM