回答

5

我的情况与你的情况略有不同,但我需要做一些类似的事情来测试整个网站的身份验证(使用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 

如果有需要跳过过滤器前,我将有一个测试,以确保它们跳过它在特定的控制器的测试特定的控制器。这不是你的情况,因为我对该方法的效果感兴趣,不仅仅知道它被调用,而且我认为我会分享以防发现它有用。

0

通常,当我想要这样的事情时,我只是测试预期的行为,而不考虑这种特定行为可能在过滤器中实现,而不是在方法本身中实现。因此,以下简单的场景:

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事情。这适用于简单的场景。如果过滤器应用于很多操作/控制器,那么您可以提取测试代码并在测试中重用它。

+0

如果过滤器是一个特定的控制器上,我同意你的做法。我的过滤器是在'ApplicationController'类中声明的(并且继承自派生自它的所有控制器)。我使用的过滤方法必须对请求进行检查。我需要在可以使用像测试具体控制器时使用的方法(或等效方法)的地方编写测试。也许你对我的问题的回答是在你的最后一句话中(“如果过滤器......在测试中”),但我看不到。另外,我如何测试附加到'before_filter'的方法是否真的附加到它? – 2012-03-17 09:52:12

+1

您可以编写一个测试套件,将其包含在每个控制器测试中并针对每个动作运行。这应该很简单(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

1

我现在认为我必须让所有控制器测试关于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具体行动。我必须在我的所有动作测试中执行此操作。

如果其他人有更好的解决方案,请告诉我。

+0

为什么不简单地测试一下使用或不使用该过滤器会发生什么?通过这种方式,您可以与过滤器分离,只关心*过滤器被调用时会发生什么,而不管它是否被调用。这样做的另一个好处是你可以重命名过滤器,改变它的范围,将它移动到其他类,或直接用观察者,服务或你有什么替换它。 – 2013-12-05 10:57:14

2

在@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 
相关问题