完善控制器的RSpec宏

时间:2010-10-19 01:48:47

标签: macros rspec2 ruby-on-rails-3

我正在尝试为使用Devise进行身份验证的Rails应用生成一个简单的宏。基本上我想确保当用户访问需要身份验证的页面时,他们会被重定向到登录页面。所以像这样:

it_requires_authentication_for :index, :new, :create, :update

这里期望的结果应该是显而易见的。然而我的问题是我无法想出将每个动作映射到适当的http方法的最佳方法(:get,:post等...)

我从这开始:

def it_should_require_authentication_for(*actions)
  actions.each do |action|
    it "should require authentication for #{action}" do
      get action.to_sym
      response.should redirect_to( new_user_session_path )
    end
  end
end

当然只有获得。有人可以告诉我如何为所有操作提供此宏吗?我假设我需要以某种方式测试动作是否适合特定方法,但我只是不确定。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:1)

可能很老,但仍然可以帮助一些人。

这是在RSpec中定义宏的一种简单方法(即使对于控制器)。

http://osmose.6spot.com.br/2011/02/better-macros-with-rspec/

看,使用缺少的方法,您可以在记录的宏中记录特定的行为,例如,这是一个带有特定存根指令的脚手架控制器规范:

describe CustomersController do

  before(:each) do
    mock_filter(:require_user_owner)
  end

  # GET /customers
  get :index do
    default :stub => :off

    before(:each) do
      Customer.stub(:find_all_by_user_id) { [mock_customer] }
    end
  end

  # GET /customers/6
  get :show, :id => 6

  # GET /customers/new
  get :new

  # GET /customers/6/edit
  get :edit, :id => 6

  # POST /customers
  post :create

  # PUT /customers/6
  put :update, :id => 6

  # DELETE /customers/6
  delete :destroy, :id => 6

end

答案 1 :(得分:0)

我正在使用以下内容,直到我想出更优雅的东西:

# controller_macros.rb
def it_should_recognize_and_generate_routes_for(controller, routes)
  describe "routing" do
    routes.each do |route|
      action   = route[:action].to_s
      method   = route[:method] || :get
      url      = controller + (route[:url] || '')
      params   = route.reject {|k, v| [:action, :method, :url].include?(k) }
      expected = { :controller => controller, :action => action }.merge(params)

      it "should recognize and generate '#{action}'" do
        { method => url }.should route_to(expected)
      end
    end
  end
end

# posts_controller_spec.rb
describe Forum::PostsController do
  it_should_recognize_and_generate_routes_for('forum/posts', [
    { :action => :new, :url => '/new' },
    { :action => :create, :method => :post },
    { :action => :show, :url => '/1', :id => '1' },
    { :action => :index },
    { :action => :edit, :url => '/1/edit', :id => '1' },
    { :action => :update, :method => :put, :url => '/1', :id => '1' },
    { :action => :destroy, :method => :delete, :url => '/1', :id => '1' }
  ])
end

BTW我仍然需要扩展它以使用以下路线:

get 'login' => 'user_sessions#new'

答案 2 :(得分:0)

此Railscast涵盖了您正在寻找的内容:http://railscasts.com/episodes/157-rspec-matchers-macros

看起来您可以在控制器规范中使用所需的操作调用get方法,它将在控制器中调用相应的方法。

这是我的宏版本:

# Last argument is an optional hash of http arguments
# which is useful when working with nested models
#
# ex it_should_require_login_for_actions(:index,:new,:create, {:parent_id=>1})
#
def it_should_require_login_for_actions(*actions)
  request_args = {:id => 1}

  #If the last element of the actions list is a hash, then merge it
  # with the existing request arguments
  if actions[-1].is_a?(Hash)
    request_args.merge!(actions.pop())
  end

  actions.each do |action|
    it "#{action} action should require login" do
      get action, request_args
      response.should redirect_to(login_url)
    end
  end
end