我使用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 }
)。
答案 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来测试这个有趣的问题)
# 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
方法可以在此上下文中定义路径。