functional/controller 测试中没有路由匹配
No route matches in functional/controller test
我使用 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
在 Whosebug 和其他地方有很多类似的问题,但它们都是指路由段被遗漏的问题(例如 PUT 上没有指定 ID)。然而,这是一个没有参数的简单 GET。
如果路由的组合方式不同,我会得到相同的结果,所以我认为这不是 root_path
位(例如 controller :foo { get 'test/index' => :index }
)。
The whole point of this is to test behavior inherited by the ApplicationController.
除了 FooController
继承自 ApplicationController
之外,您的问题中没有与 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
我搜索了你提供的信息。我在 rspec-rails
gem 中发现了一个未解决的问题。然而 gem 在这里并不重要,但从根本上说,他们说的是它的上下文问题。当您调用 with_routing
时,它不会在正确的上下文中执行,因此会给出 No Route matches 错误。
为了解决问题,我在本地尝试了不同的解决方案。这是我试过的
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!
方法重现路由。
希望对你有所帮助!!
更新
我试图理解你最后的评论并深入研究 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
如果您检查 ActionController::TestCase#get
方法的来源,它需要操作名称,例如:index, :create, '编辑, 'create'
如果您在 #get
方法上传递 root_path
,绝对会引发错误,因为 root_path
方法 returns '/'。
我刚刚检查了将 :/ 方法添加到 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):
回复
我认为'/'是不允许对rails进行操作的,我没有进一步研究,因为我认为这是非常合理的。
你可以写
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
这个问题的解决方案比预期的要简单得多:
# change this:
get(root_path)
# to this
get(:index)
with_routing
方法可以很好地定义此上下文中的路径。
我使用 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
在 Whosebug 和其他地方有很多类似的问题,但它们都是指路由段被遗漏的问题(例如 PUT 上没有指定 ID)。然而,这是一个没有参数的简单 GET。
如果路由的组合方式不同,我会得到相同的结果,所以我认为这不是 root_path
位(例如 controller :foo { get 'test/index' => :index }
)。
The whole point of this is to test behavior inherited by the ApplicationController.
除了 FooController
继承自 ApplicationController
之外,您的问题中没有与 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
我搜索了你提供的信息。我在 rspec-rails
gem 中发现了一个未解决的问题。然而 gem 在这里并不重要,但从根本上说,他们说的是它的上下文问题。当您调用 with_routing
时,它不会在正确的上下文中执行,因此会给出 No Route matches 错误。
为了解决问题,我在本地尝试了不同的解决方案。这是我试过的
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!
方法重现路由。
希望对你有所帮助!!
更新
我试图理解你最后的评论并深入研究 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
如果您检查 ActionController::TestCase#get
方法的来源,它需要操作名称,例如:index, :create, '编辑, 'create'
如果您在 #get
方法上传递 root_path
,绝对会引发错误,因为 root_path
方法 returns '/'。
我刚刚检查了将 :/ 方法添加到 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):
回复
我认为'/'是不允许对rails进行操作的,我没有进一步研究,因为我认为这是非常合理的。
你可以写
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
这个问题的解决方案比预期的要简单得多:
# change this:
get(root_path)
# to this
get(:index)
with_routing
方法可以很好地定义此上下文中的路径。