如何在Rails 3中的过滤方法之前测试应用程序控制器?

时间:2012-03-17 07:26:06

标签: ruby-on-rails ruby-on-rails-3 testing functional-testing before-filter

我的before_filter课程上有ApplicationController,我想为它编写测试?我应该把这个测试写在哪里?我不想进入每个子类控制器测试文件并重复关于此过滤器的测试。

因此,测试ApplicationController before_filters的推荐方法是什么?

请注意,我将Rails 3.2.1minitest一起使用。

4 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:2)

改进@bmaddy应答器,您需要为要运行的规范设置路由。

以下是rails 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

答案 2 :(得分: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。我必须在我的所有行动测试中这样做。

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

答案 3 :(得分: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的东西。这适用于简单的场景,非常好。如果过滤器应用于许多操作/控制器,那么您可以提取测试代码并在测试中重复使用。