DRYing out controller specs?

I’d like to DRY out my controller specs but am having difficulties doing
so and am hopeful that a more experienced rspec expert can shed some
much-needed light on my woes…

The controllers themselves are using josevalim’s wonderful
inherited_resources gem, so they are incredibly small - I’m basically
looking for something like this on the rspec side…

I’m hoping to find a way to:

  • Define a set of shared examples for each of the 7 common RESTful
    actions (index, show, new, edit, create, update, destroy)

  • include those shared examples in a number of controllers
    (ApplesController, OrangesController)

  • obviously have the shared examples know about the model names,
    something like:

    assigns[@model_name.to_sym].should be_new_record # GET …/new

  • not so obviously have the description of the example reflect the model
    names:

    it “should delete the #{@model_name}” do

  • be very DRY: Ideally, apples_controller_spec and
    oranges_controller_spec would be small: mostly about initialization of
    config (e.g. the model name) and include the various shared specs which
    tested the controller.

I’ve played around with a lot of approaches, but cannot figure out a
clean pattern in which variables such as @model_name are scoped visible
to the ‘it’ descriptions AND the example blocks. I’m probably missing
some wonderful clean ruby-way of doing this.

Thoughts/advice much appreciated!
-Eric

On Thu, Sep 24, 2009 at 8:13 PM, Eric H. [email protected] wrote:

The controllers themselves are using josevalim’s wonderful inherited_resources gem, so they are incredibly small - I’m basically looking for something like this on the rspec side…

(googling) Aha. Looks a lot like the old make_resourceful,
resource_controller, and resources_controller plugins. Not sure I
agree with his choice to drive it by class inheritance rather than
module inclusion, though. Seems like it might be pretty fragile –
which he corroborates with his note that RSpec in standard controller
isolation mode breaks it.

I’ve played around with a lot of approaches, but cannot figure out a clean pattern in which variables such as @model_name are scoped visible to the ‘it’ descriptions AND the example blocks. I’m probably missing some wonderful clean ruby-way of doing this.

Class variables may be your friend here, since the “it” descriptions
are really akin to method definitions and therefore declared at the
class level.

That said, though: I have to wonder if it’s a good idea to have so
much magic that all of your controller specs now declare themselves
almost completely in shared examples. That makes the behavior
specification invisible, at least at a fast code glance. Half the
reason I write specs is because typing them makes me take a moment to
think about the behavior I want. If your controllers are so uniform
that you not only don’t have to write them, you don’t have to write
the specs for them – then why test them? Why not just make sure
your inherited_resources suite has a thorough set of specs, and trust
it to act consistently, only spec’ing the variances?

(Yes, this is sort of a cynic’s view. It’s the same reason I
eventually stopped using make_resourceful – too much magic. The
actual meat of my controllers was so well-hidden that I found myself
looking at the plugin’s docs constantly just to remember what my own
application did.)


Have Fun,
Steve E. ([email protected])
ESCAPE POD - The Science Fiction Podcast Magazine
http://www.escapepod.org