[rspec-devel] rspec_on_rails, speccing models, adding it helpers...
Bart Zonneveld
loop at superinfinite.com
Thu Apr 3 03:45:12 EDT 2008
On 3-apr-2008, at 5:01, Tim Haines wrote:
> I totally agree. This sort of comment/guidance/opinion should be
> findable from (or included on) the rspec.info page on models..
+1
I was thinking along the same lines as Pat when I first was speccing
my models with behaviours.
However, I still use specs like:
it "should have many comments"
Post.should have_many(:comments).depending
end
and be done with it.
See http://stevetooke.karmatrading.co.uk/2007/8/10/simple-rails-
association-matching-with-rspec
I like the way I can write the spec now. It should have many
comments. Red. has_many :comments, :dependent => :destroy. Green.
Commit. Be done with it :).
cheers,
bartz
> Pat - thanks a bunch for taking the time!
>
> Tim.
>
> On 03/04/2008, David Chelimsky <dchelimsky at gmail.com> wrote: On
> Wed, Apr 2, 2008 at 10:40 PM, Zach Dennis <zach.dennis at gmail.com>
> wrote:
> > Pat,
> >
> > That was a wonderfully thought out reply and at first read your
> > reasoning makes a lot of sense.
>
>
> +1
>
>
> > Thank you for taking the time to write
> > it.
>
>
> +1 more
>
> Cheers,
>
> David
>
>
> > I am going to let it sink in over the next few days,
> >
> > Zach
> >
> >
> >
> >
> > On Wed, Apr 2, 2008 at 8:11 PM, Pat Maddox <pergesu at gmail.com>
> wrote:
> > >
> > > On Tue, Apr 1, 2008 at 4:20 PM, Zach Dennis
> <zach.dennis at gmail.com> wrote:
> > > >
> > > > On Tue, Apr 1, 2008 at 6:38 PM, Pat Maddox
> <pergesu at gmail.com> wrote:
> > > > > On Tue, Apr 1, 2008 at 3:09 PM, David Chelimsky
> <dchelimsky at gmail.com> wrote:
> > > > > > > Example:
> > > > > > >
> > > > > > > describe SomeModel do
> > > > > > > it_has_many :widgets, :destroy
> => :null, :class_name => "BaseWidget"
> > > > > > > it_has_one :fuzzbucket
> > > > > > > it_belongs_to :another_model
> > > > > > > end
> > > > > >
> > > > > > I see more and more structures appearing like this.
> I have very mixed
> > > > > > feelings about them. This is about structure, not
> behaviour. Even if
> > > > > > the underlying code is actually approaching this in
> a more behavioural
> > > > > > way, it's still expressing structure at the high level.
> > > > >
> > > > > I don't have mixed feelings about this. I think this
> type of spec is
> > > > > terrible. It completely duplicates the
> implementation. It's not even
> > > > > testing anything.
> > > > >
> > > > > This is not a value judgment against you though, Zach.
> I think when
> > > > > people do stuff like this they genuinely have good
> intentions. It's
> > > > > just that it seems to be quite difficult to test highly
> declarative
> > > > > stuff like AR associations.
> > > > >
> > > > > Now that I've given my rather harsh opinion, I have to
> get back to
> > > > > work :) I'll try follow up later with something more
> helpful like
> > > > > thoughts on how to write better specs.
> > > > >
> > > >
> > > > I don't like the fact that it tests the structure of the
> association
> > > > (as opposed to testing the behavior), but I do like that
> it tests the
> > > > conceptual relationship between models. I find value in
> this. Even
> > > > though it is declarative it is very clear and meaningful
> to the next
> > > > guy looking at the code, and if someone changes something
> incidentally
> > > > they are quickly pointed to the fact that they broke a
> conceptual
> > > > relationship between two models.
> > > >
> > > > Please do respond with more thoughts, as this is a topic
> I'd like to
> > > > get hammered out as it will provide value to every
> developer on this
> > > > list,
> > >
> > > I've put some more thought into this and have a bit of time
> to reply.
> > > So here goes.
> > >
> > > The first thing I'm going to do is demonstrate why I feel
> this is a
> > > bad spec. Please understand that this is not a criticism of
> anyone in
> > > particular. I'm merely using this as an example of specs
> that don't
> > > add any value.
> > >
> > > Take a look at the spec again:
> > >
> > >
> > > describe SomeModel do
> > > it_has_many :widgets, :destroy => :null, :class_name =>
> "BaseWidget"
> > > it_has_one :fuzzbucket
> > > it_belongs_to :another_model
> > > end
> > >
> > > Change 'describe' to 'class' and remove 'do' from the first
> line.
> > > Then remove the 'it_' from the next three lines. At this
> point you
> > > have the exact implementation of the class.
> > >
> > > I don't know about you, but that bothers the hell out of me.
> > >
> > > The concrete benefits of object-level specification are, in
> my mind, that it
> > > - helps you design your code well
> > > - leaves behind regression tests
> > > - provides executable examples of how to use code
> > >
> > > Often when we write specs we have to balance those goals...for
> > > example, one major criticism of using mocks is that tests
> that use
> > > mocks don't act as effective regression tests. That's a valid
> > > criticism in certain contexts, but you'll find that most
> people who
> > > make such criticisms are being myopic - they either don't
> understand
> > > or don't share the other goals, and so write the technique
> off all
> > > together.
> > >
> > > Besides the fact that the given association helpers duplicate
> the
> > > implementation to an i-t-underscore, what else is wrong with
> them? I
> > > would argue that they provide 0 value in all three categories.
> > >
> > > They don't help drive the design. You either need widgets or
> you
> > > don't. If you decide you do, you add a declaration to the
> > > implementation. Done. There was never any question about
> how to
> > > design it. Rails made that decision for you.
> > >
> > > They have no value as regression tests. How likely is it
> that any of
> > > that code will break? Not likely at all. It's not like
> anyone's ever
> > > going to go in there and change the behavior, because there
> is no
> > > behavior, other than that which is abstracted away by Rails
> (thus
> > > already thoroughly tested). If you make any change to the
> > > implementation then the specs will fail...so they're brittle
> without
> > > providing any value.
> > >
> > > The lack of documentation value should be obvious. The specs
> don't
> > > show you how to use the objects together. You have to know
> how Rails
> > > associations work. And you get absolutely no information
> from the
> > > spec that you don't get from the implementation itself.
> > >
> > > Hopefully that clarifies why I don't feel that specs like
> these are
> > > valuable. I also hope that this helps others develop
> heuristics for
> > > when to write/delete/ignore tests.
> > >
> > > With that out of the way, how would I specify this SomeModel
> class?
> > > Well, if the class is as given and there's no business logic,
> then I
> > > would only write a couple specs for SomeModel directly.
> These would
> > > be specs for the widgets association.
> > >
> > > describe SomeModel, "widgets" do
> > > before(:each) do
> > > @model = SomeModel.create!
> > > BaseWidget.create! :some_model_id => @model.id
> > > end
> > >
> > > it "should find BaseWidgets" do
> > > @model.should have(1).widget
> > > end
> > >
> > > it "should nullify keys when deleting the widgets" do
> > > lambda { @model.widgets.destroy_all }.should_not change
> (BaseWidget, :count)
> > > @model.should have(0).widgets
> > > end
> > > end
> > >
> > > The reason I would do this is because there's a greater
> chance that
> > > some of this stuff could break. None of the other
> associations will.
> > >
> > > Looking back at this, I'm not sure that I would write the second
> > > example. The reason I might not write it is that I don't
> think I have
> > > enough information. The foreign keys get nulled out when I call
> > > #destroy_all, but that's something that I know from the has_many
> > > declaration, and that I know works. My real question at this
> point is
> > > WHY I want the keys nulled out instead of just deleting the
> records.
> > > Do I have some requirement in the system that these associations
> > > should be broken, but the child records should stick around?
> If so, I
> > > should have another spec that demonstrates that behavior.
> > >
> > > These associations *should* be tested, but they should be tested
> > > indirectly from _somewhere else_. They're not important
> enough to
> > > deserve tests at such a low granularity. They should be
> tested via an
> > > acceptance test where a view iterates through them, or some
> test which
> > > calls a DB aggregate method on the proxy. They don't have any
> > > interesting behavior on their own, and we are concerned
> primarily with
> > > behavior.
> > >
> > > Does that help?
> > >
> > > Pat
> > >
> >
> >
> >
> >
> > --
> > Zach Dennis
> > http://www.continuousthinking.com
> > _______________________________________________
> >
> >
> > rspec-devel mailing list
> > rspec-devel at rubyforge.org
> > http://rubyforge.org/mailman/listinfo/rspec-devel
> >
> _______________________________________________
> rspec-devel mailing list
> rspec-devel at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-devel
>
> _______________________________________________
> rspec-devel mailing list
> rspec-devel at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-devel
More information about the rspec-devel
mailing list