功能/控制器测试中没有路由匹配

时间:2016-03-01 02:02:39

标签: ruby-on-rails routes minitest

我使用Minitest :: Rails和Rails进行了以下控制器测试4.当我运行它时,我收到一个错误:ActionController::UrlGenerationError: No route matches {:action=>"/", :controller=>"foo"}错误,尽管它被定义了。

这一点的重点是测试ApplicationController上的方法(FooController仅存在于此测试中,并且不是问题的占位符)。

class FooController < ApplicationController
  def index
    render nothing: true
  end
end

class FooControllerTest < ActionController::TestCase
  it 'does something' do
    with_routing do |set|
      set.draw do
        root to: 'foo#index', via: :get
      end

      root_path.must_equal '/' #=> 
      get(root_path).must_be true #=> No route matches error
    end
  end
end

在StackOverflow和其他地方有许多类似的问题,但它们都涉及遗漏路径段的问题(例如,在PUT上没有指定ID)。然而,这是一个没有参数的简单GET。

如果路线的汇编方式不同,我会得到相同的结果,所以我不认为root_path位是这样做的(例如controller :foo { get 'test/index' => :index })。

4 个答案:

答案 0 :(得分:2)

我搜索了您提供的信息。我在rspec-rails gem中发现了一个问题。然而,宝石在这里并不重要,但从根本上说,他们说它的背景问题。当您致电with_routing时,它没有在正确的上下文中执行,因此会出现无路线匹配错误。

要解决问题,我尝试了不同的解决方案。这是我试过的

require 'rails_helper'

RSpec.describe FooController, type: :controller do
  it 'does something' do

    Rails.application.routes.draw do
      root to: 'foo#index', via: :get
    end

   expect(get: root_path).to route_to("foo#index")

  end
end

在上面的代码中,主要问题是它会覆盖现有路由。但我们可以使用Rails.application.reload_routes!方法重现路线。

我希望这对你有帮助!!

<强> UPDTATE

我尝试了解您的上一条评论并深入了解get方法。当我们调用get方法时,它会接受我们正在测试的控制器的动作参数。在我们执行get(root_path)的情况下,它会尝试查找不存在的foo#/,因此不会给出路由匹配错误。

由于我们的主要目标是检查root_path路由是否正确生成,我们需要使用方法assert_routing来检查它。这是我测试的方式,它的工作原理 assert_routing root_path , controller: "foo", action: "index"

完整代码:

require 'test_helper'

class FooControllerTest < ActionController::TestCase
  it 'does something' do
    with_routing do |set|
      set.draw do
        root to: 'foo#index', via: :get
      end

      root_path.must_equal '/' #=> true
      assert_routing root_path , controller: "foo", action: "index" #=> true
      get :index
      response.body.must_equal ""
    end
  end
end

我从官方文件中读到了这些内容:http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html

答案 1 :(得分:2)

如果您检查ActionController::TestCase#get方法的来源,则需要操作名称,例如:index,:create,'edit,'create'

如果您在root_path方法上通过#get,则绝对会引发错误,因为root_path方法会返回'/'。 我刚刚检查了将:/方法添加到FooController

class FooController
  def index
  end

  def /
  end
end

Rails.application.routes.draw do
  root 'foo#index'
  get 'foobar' => 'foo#/'
end

当我访问http://localhost:3000/foobar时,rails给了我 AbstractController::ActionNotFound (The action '/' could not be found for FooController):回复

我认为'/'不允许在轨道上行动,我不做进一步研究,因为我认为这是非常合理的。

你可以写 assert_routing '/', controller: "foo", action: "index" 对于当前测试,您可以编写集成测试来检查root_path和其他功能。

以下是我上面讨论的一些方法的源代码:(我使用rails 4.2.3来测试这个有趣的问题)

action_controller / test_case.rb

  # Simulate a GET request with the given parameters.
  #
  # - +action+: The controller action to call.
  # - +parameters+: The HTTP parameters that you want to pass. This may
  #   be +nil+, a hash, or a string that is appropriately encoded
  #   (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
  # - +session+: A hash of parameters to store in the session. This may be +nil+.
  # - +flash+: A hash of parameters to store in the flash. This may be +nil+.
  #
  # You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
  # +post+, +patch+, +put+, +delete+, and +head+.
  #
  # Note that the request method is not verified. The different methods are
  # available to make the tests more expressive.
  def get(action, *args)
    process(action, "GET", *args)
  end


  # Simulate a HTTP request to +action+ by specifying request method,
  # parameters and set/volley the response.
  #
  # - +action+: The controller action to call.
  # - +http_method+: Request method used to send the http request. Possible values
  #   are +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, +HEAD+. Defaults to +GET+.
  # - +parameters+: The HTTP parameters. This may be +nil+, a hash, or a
  #   string that is appropriately encoded (+application/x-www-form-urlencoded+
  #   or +multipart/form-data+).
  # - +session+: A hash of parameters to store in the session. This may be +nil+.
  # - +flash+: A hash of parameters to store in the flash. This may be +nil+.
  #
  # Example calling +create+ action and sending two params:
  #
  #   process :create, 'POST', user: { name: 'Gaurish Sharma', email: 'user@example.com' }
  #
  # Example sending parameters, +nil+ session and setting a flash message:
  #
  #   process :view, 'GET', { id: 7 }, nil, { notice: 'This is flash message' }
  #
  # To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE+ and +HEAD+ requests
  # prefer using #get, #post, #patch, #put, #delete and #head methods
  # respectively which will make tests more expressive.
  #
  # Note that the request method is not verified.
  def process(action, http_method = 'GET', *args)
    # ..... 
  end

答案 2 :(得分:0)

  

这一点的全部意义是测试ApplicationController继承的行为。

除了ApplicationController继承自FooController这一事实外,您的问题中没有与ApplicationController相关的行为。并且因为在FooController中没有其他行为可以与Application Controller中的某些内容相关...

你可以测试一下

class FooController < ApplicationController
  def index
    render nothing: true
  end
end

用这个

describe FooController, type: :controller do
  describe '#index' do
    it 'does not render a template' do
      get :index
      expect(response).to render_template(nil)
    end
  end
end

答案 3 :(得分:0)

这个问题的解决方案比预期的要简单得多:

# change this:
get(root_path)

# to this
get(:index)

with_routing方法可以在此上下文中定义路径。