[rspec-users] Depot app, Demeter's law and troubles cleanly spe cing

Stephen Eley sfeley at gmail.com
Thu Apr 23 15:40:20 EDT 2009

On Thu, Apr 23, 2009 at 2:19 PM, Fernando Perez <lists at ruby-forum.com> wrote:
> Rails definitely entices you to break Demeter's law just so often.

So fix it.  It's usually just a matter of putting in some delegators.
If you don't like @article.comments.build, you can declare your own
Article.build_comment() method and simply have it point to the
comment's method.  Or call it something else if you don't like the
word "build."  (I don't.)

> Now how to cleanly spec:
> @comment = @article.comments.build(params[:comment]) ?

That's backwards.  If you already have a line of code and you're
asking how to write a spec for it, you're not honoring the behavior.
You're honoring that line of code.

I'm going to guess from knowledge of the idiom that this is for a
'create' method in the CommentsController, nested under
ArticlesController.  Whether it calls 'comments.build' or
'comments.create' or 'make_me_a_comment!' isn't important and doesn't
need to be specified.  What's important is the end result of the
method, which is that the article gains a shiny new comment:

# Assume an article with no comments and a params structure
# have already been set up in before(:each)

it "should make a new comment belonging to the article" do
  post :create, :comment => @my_valid_params
  @my_article.should have(1).comment

How clean is that?  Now just a couple more specs for *invalid* params
and for where the method directs to, and you're basically done.

> Mocking and stubbing is starting to get ugly now.

That much is true.  You'll notice I didn't mock or stub anything up
there.  I honestly think the controller code by the RSpec scaffold
generator is the wrong approach; it's specing implementation, not
behavior.  Even worse, it's specing the implementation details of
*model* code, which shouldn't even be a consideration here.  My way
breaks isolation (it hits the database) but it's a lot simpler and
focuses on behavior.

Is it possible to get behavior focus *and* isolation?  I started to
think about that.  And then I realized, in accordance with the "If
it's hard to spec you're probably doing it wrong" principle,
that...well, Rails is probably doing it wrong.  Controllers in Rails
are just doing the Wrong Thing.  That's why specing them is so
painful, and why so many of us skip trying.

What's the right way?  I'm still pondering.

Yeah, I'm a smartass.

Have Fun,
   Steve Eley (sfeley at gmail.com)
   ESCAPE POD - The Science Fiction Podcast Magazine

More information about the rspec-users mailing list