我在ApplicationController
课上有before_filter
,我想为它编写一个测试?我应该在哪里写这个测试?我不想进入每个子类控制器测试文件并重复有关此过滤器的测试。如何在Rails 3中的过滤方法之前测试应用程序控制器?
因此,什么是测试ApplicationController
before_filters的推荐方式?
请注意,我使用Rails 3.2.1
和minitest
。
我在ApplicationController
课上有before_filter
,我想为它编写一个测试?我应该在哪里写这个测试?我不想进入每个子类控制器测试文件并重复有关此过滤器的测试。如何在Rails 3中的过滤方法之前测试应用程序控制器?
因此,什么是测试ApplicationController
before_filters的推荐方式?
请注意,我使用Rails 3.2.1
和minitest
。
我的情况与你的情况略有不同,但我需要做一些类似的事情来测试整个网站的身份验证(使用Devise)。以下是我做的:
# application_controller.rb
class ApplicationController < ActionController::Base
before_filter :authenticate_user!
end
# application_controller_test.rb
require 'test_helper'
class TestableController < ApplicationController
def show
render :text => 'rendered content here', :status => 200
end
end
class ApplicationControllerTest < ActionController::TestCase
tests TestableController
context "anonymous user" do
setup do
get :show
end
should redirect_to '/users/sign_in'
end
end
如果有需要跳过过滤器前,我将有一个测试,以确保它们跳过它在特定的控制器的测试特定的控制器。这不是你的情况,因为我对该方法的效果感兴趣,不仅仅知道它被调用,而且我认为我会分享以防发现它有用。
通常,当我想要这样的事情时,我只是测试预期的行为,而不考虑这种特定行为可能在过滤器中实现,而不是在方法本身中实现。因此,以下简单的场景:
class Controller < ApplicationController
before_filter :load_resource, :only => [:show, :edit]
def show
end
def edit
end
def index
end
#########
protected
#########
def load_resource
@resource = Model.find(params[:id])
end
end
我会简单测试#show和#edit分配@resource事情。这适用于简单的场景。如果过滤器应用于很多操作/控制器,那么您可以提取测试代码并在测试中重用它。
我现在认为我必须让所有控制器测试关于before_filter存在的测试,并且此过滤器按预期工作。这是因为,我不知道控制器是否应该使用skip_before_filter
。
因此,我决定使用mock
(@controller.expects(:before_filter_method)
)来确保过滤器被调用。因此,例如,在index
行动我写在我的测试:
test "get index calls the before filter method" do
@controller.expects(:before_filter_method)
# fire
get :index
end
这将确保我的控制器调用before_filter_method
具体行动。我必须在我的所有动作测试中执行此操作。
如果其他人有更好的解决方案,请告诉我。
为什么不简单地测试一下使用或不使用该过滤器会发生什么?通过这种方式,您可以与过滤器分离,只关心*过滤器被调用时会发生什么,而不管它是否被调用。这样做的另一个好处是你可以重命名过滤器,改变它的范围,将它移动到其他类,或直接用观察者,服务或你有什么替换它。 – 2013-12-05 10:57:14
在@bmaddy answser上改进,您需要设置路由以使规格运行。
这里有一个导轨5个例子:
require 'test_helper'
class BaseController < ApplicationController
def index
render nothing: true
end
end
class BaseControllerTest < ActionDispatch::IntegrationTest
test 'redirects if user is not logedin' do
Rails.application.routes.draw do
get 'base' => 'base#index'
end
get '/base'
assert_equal 302, status
assert_redirected_to 'http://somewhere.com'
Rails.application.routes_reloader.reload!
end
test 'returns success if user is loggedin' do
Rails.application.routes.draw do
get 'base' => 'base#index'
end
mock_auth!
get '/base'
assert_equal 200, status
Rails.application.routes_reloader.reload!
end
end
如果过滤器是一个特定的控制器上,我同意你的做法。我的过滤器是在'ApplicationController'类中声明的(并且继承自派生自它的所有控制器)。我使用的过滤方法必须对请求进行检查。我需要在可以使用像测试具体控制器时使用的方法(或等效方法)的地方编写测试。也许你对我的问题的回答是在你的最后一句话中(“如果过滤器......在测试中”),但我看不到。另外,我如何测试附加到'before_filter'的方法是否真的附加到它? – 2012-03-17 09:52:12
您可以编写一个测试套件,将其包含在每个控制器测试中并针对每个动作运行。这应该很简单(r)使用'it_behaves_like'来使用RSpec(https:// www。relishapp.com/rspec/rspec-core/v/2-0/docs/example-groups/shared-example-group)的东西,但在简单的Test :: Unit上你可以做这样的事情。也许你可以从ActiveModel :: Lint:Tests中获得灵感(http://api.rubyonrails.org/classes/ActiveModel/Lint/Tests.html - https://github.com/rails/rails/blob/master/activemodel /lib/active_model/lint.rb) – 2012-03-17 10:00:21