开发者

Perfecting an RSpec macro for controllers

I'm trying to generate an easy macro for a Rails app that uses Devise for authentication. Basically I want to ensure that when a user accesses a page that requires authentication, they're redirected to the login page. So something like this:

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

The desired results here should be obvious. My problem however is that I can't think of the best way to map each action to its appropriate http method (:get, :post etc...)

I started out with this:

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

Which of course only does the get. Can someone tell me how I might provide this macro for all actions? I'm assuming I need to somehow test if the action routes properly for a particular method, but I'm just not really sure.

Any help is greatly apprecia开发者_如何学Goted.


maybe old, but still can help some.

Here is a nice and easy way to define macros in RSpec (even for controllers).

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

Look, using method missing you are able to record specific behavior into your recorded macros, for instance, this is a scaffold controller spec with a specific stub instruction:

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


I'm using the following until I come up with something more elegant:

# 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 I still have to extend it to work with routes like:

get 'login' => 'user_sessions#new'


This Railscast covers exactly what you are looking for: http://railscasts.com/episodes/157-rspec-matchers-macros

It looks like you can just call the get method with your desired action in your controller spec, and it will call the appropriate method in the controller.

Here is my version of the macro:

# 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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜