我正试图孤立地测试我的控制器的动作链。具体来说,我想确保我所需的行为适用于我所有控制器的操作。例如,测试我的所有操作都需要身份验证:
context "when not authenticated" do
# single case
describe "GET index" do
it "responds with 401" do
get :index
response.code.should be(401)
end
end
# all of them...
described_class.action_methods.each do |action|
['get', 'put', 'post', 'delete', 'patch'].each do |verb|
describe "#{verb.upcase} #{action}" do
it "responds with 401" do
send verb, action
response.code.should == "401"
end
end
end
end
end
我希望这可行,但事实并非如此。我得到了一些ActionController::RoutingErrors
。这是因为我的一些路线需要参数,在某些情况下我不提供它们(就像我打电话给post :create
时)。我明白了。但我不明白的是:为什么应该重要!?
对于这些测试,路由是一个单独的问题。我关心的是我的行动链,而不是我的要求(这就是我routing specs
和request specs
所要求的。我不应该关心自己在这个级别的路线限制。
所以我的问题是:有没有办法在不模拟请求的情况下测试动作链?
编辑:一些研究
看起来在TestCase#process中正在行使路线。这有必要吗?
答案 0 :(得分:6)
解决方法是放松路由引擎的约束。这不会绕过路由,但它确实可以更容易地进行测试。
在您的规范中添加以下内容:
before(:all) do
Rails.application.routes.draw { match ':controller(/:action)' }
end
after(:all) do
Rails.application.reload_routes!
end
虽然不是问题的严格答案,但这可能是一个很好的解决方法。
答案 1 :(得分:2)
我认为路由不是控制器规范的单独考虑因素。其中一个原因是,根据传递给url的值将值添加到params散列中,并且控制器中的代码可能依赖于这些值。
无论如何,我假设您在ApplicationController
中定义了某种授权方法。单独测试每个控制器似乎有点多余。我就是这样做的:
require "spec_helper"
describe ApplicationController do
describe "require_current_user" do
ACTIONS_AND_VERBS = [
[:index, :get],
[:show, :get],
[:new, :get],
[:create, :post],
[:edit, :get],
[:update, :put],
[:destroy, :delete],
]
controller do
ACTIONS_AND_VERBS.each do |action, _|
define_method(action) do
end
end
end
ACTIONS_AND_VERBS.each do |action, verb|
describe "#{verb.to_s.upcase} '#{action}'" do
it "should be successful" do
send(verb, action, id: -1)
response.code.should eq("401")
end
end
end
end
end
在我的ApplicationController
我有类似......
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :require_current_user
def require_current_user
head :unauthorized
end
end
编辑:如果我理解正确,我们真正测试的是您的require_current_user
或任何您想要发生的等效授权过程正在按预期工作。在这种情况下,我们只能测试一个操作,并相信before_filter
正常工作。
require "spec_helper"
describe ApplicationController do
describe "require_current_user" do
controller do
def index
end
end
it 'should head unauthorized for unauthorized users' do
get :index
response.code.should eq("401")
end
end
end