[RSpec] Clarification on using shared_examples_for on a Rails Controller


#1

I have a Rails controller that I am using ‘before_filter’ on certain
actions
to assign some extra variables. I noticed the ‘shared_examples_for’
method
and thought this would be a good way to test that the given actions are
loading what they need. I wrote the following:

shared_examples_for ‘pages showing the yearly archive’ do

it 'should assign a list of yearly archives' do
  Factory.create(:post, :published_at => Time.local(2009,02,01))
  Factory.create(:post, :published_at => Time.local(2009,01,01))
  Factory.create(:post, :published_at => Time.local(2008,01,01))
  Factory.create(:post, :published_at => Time.local(2007,01,01))
  Factory.create(:post, :published_at => Time.local(2001,01,01))

  get :index

  assigns[:years].should == [ 2009, 2008, 2007, 2001 ]
end

end

The problem is, it is specific to the ‘index’ action. I can’t use the
‘it_should_behave_like “pages showing the yearly archive”’ for other
actions.

Am I just doing this wrong or is there a way to fix this?

  • Stephen H. Gerstacker

#2

On Wed, Apr 22, 2009 at 10:04 AM, Stephen H. Gerstacker
removed_email_address@domain.invalid wrote:

  Factory.create(:post, :published_at => Time.local(2008,01,01))

The problem is, it is specific to the ‘index’ action. I can’t use the
‘it_should_behave_like “pages showing the yearly archive”’ for other
actions.

Assign the action to an instance variable and set it to the desired
value in a before(:all) in each of the sharers. In the shared example,
do get @action.

///ark


#3

On Wed, Apr 22, 2009 at 12:04 PM, Stephen H. Gerstacker
removed_email_address@domain.invalid wrote:

  Factory.create(:post, :published_at => Time.local(2008,01,01))

The problem is, it is specific to the ‘index’ action. I can’t use the
‘it_should_behave_like “pages showing the yearly archive”’ for other
actions.

Am I just doing this wrong or is there a way to fix this?

Shared examples don’t support parameterization, but macros do. Try
something like this:

module Macros
def shows_yearly_archive_for(requests={})
requests.keys.each do |action|
it “should assign a list of yearly archives on
#{requests[action]} #{action}” do
Factory.create(:post, :published_at => Time.local(2009,02,01))
Factory.create(:post, :published_at => Time.local(2009,01,01))
Factory.create(:post, :published_at => Time.local(2008,01,01))
Factory.create(:post, :published_at => Time.local(2007,01,01))
Factory.create(:post, :published_at => Time.local(2001,01,01))

    send requests[action], action

    assigns[:years].should == [ 2009, 2008, 2007, 2001 ]
  end
end

end
end

describe SomeController do
extend Macros
shows_yearly_archive_for :index => :get
end

You can also extend with Macros from the config in spec_helper:

Spec::Runner.configure {|c| c.extend(Macros, :type => :controller)}

HTH,
David

ps - completely un-tested - that was off the top of my head


#4

----- Original Message ----

From: David C. removed_email_address@domain.invalid

Shared examples don’t support parameterization, but macros do. Try
something like this:

module Macros
def shows_yearly_archive_for(requests={})
[…]
end
end

describe SomeController do
extend Macros
shows_yearly_archive_for :index => :get
end

Nice. This must be newish (I see it in book beta4 - good!). I’d been
using callbacks defined in the example group next to
it_should_behave_like() to get any relevant parameters. A bit icky,
I’ll admit. So I can just pass the details from the callback directly
to the macro, when I port it/them. Sweet.

I’ve been using a pattern for my shared example groups, similar to one I
correlate (erroneously?) to a Ben M. post. The original pattern:
do_foo(), where foo is get, post, whatever and the shared example probes
the calling example group to find which one is relevant.

My variation is do_action(), where the example group directly defines
do_action() in whatever way is suitable to the example group (using
instance variables set by before blocks, etc). This method could be
defined usefully by either a Controller example group or a Model example
group.

I feel like even when using macros, I’d want to continue using my
do_action() pattern. But maybe I have a hammer and so I’m looking for a
nail.

Is there another approach that gives different/better value when using
macros?

Thanks,

Randy