2009/4/24 Stephen Eley <[email protected]>

> On Thu, Apr 23, 2009 at 2:19 PM, Fernando Perez <[email protected]>
> wrote:
>
> [...]
>
> # 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
> end
>
> 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.


Amen to that.


> > 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.


And amen to that too.

Even within an rspec example I think of each line of code as a Given
(setup), When (event) or Then (outcome). Usually when I see a line doing
more than one of these - say calling a method and verifying its result - I
break it out into separate event and outcome lines.

The reason for this is that the givens and outcomes can tinker with whatever
they want. They can create mocks, poke around in the database, wire up
models, whatever. The event lines though - the Whens - can only interact
with the object like client code would. In other words they can't know that
an object is a mock, or that a value got into a database because you poked
it there.

Your example is great. You have an event line that interacts with the
controller through a regular HTTP POST, like a client would, and you verify
that by checking the database via the ActiveRecord model object. There is no
need for a mock here if your example is checking that data ends up in the
database (although that does make it more of an integration test than a
behavioural spec). Because of rails's evil insistence that a "model" is just
a persistence strategy, they are pretty much the same thing.

Is it possible to get behavior focus *and* isolation?


Yes, but it only has value on a per-line-of-code-in-your-spec basis. Your
givens and outcomes shouldn't care about isolation - your events should only
be exercising behaviour that is available in the object you are describing.

It gets more complicated when a single line of code both exercises behaviour
and does verification. I find breaking these out helps my sanity.

 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.


Me too!


> Yeah, I'm a smartass.


Well you seem to be on the right lines to me.

Cheers,
Dan
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to