[rspec-users] reusable specs - almost there

Pat Maddox
Sun, 05 Aug 2007 20:18:15 -0000

I agree with David, I think this is too much magic.

You''ll often have more duplication in specs than you will in
production code.  That''s not a bad thing though, because specs need to
be explicit about the behavior being performed.  Duplication doesn''t
lead to the same mistakes that it does in production code.

You can and should factor out stuff when doing so won''t hurt the
clarity of the specs.  However when you have to think hard to figure
out what''s going on, you lose one of the main benefits of RSpec.
It''s
all about making your spec code easy to parse.

Solving the problem of 14 different shared contexts isn''t really hard.

%w(admin_context regular_user_context manager_context).each do |con|
  describe MyController do
    it_should_be_have_like con
  end
end

Pat

On 8/5/07, David Green <justnothing at tiscali.co.uk>
wrote:
>
> that''s a great point, but there are some things about shared
behaviours I
> don''t like. for example, I have 14 different contexts I''m
testing (and more
> to come) in 8 controllers.
>
> I can do this:
>
> describe MyController do
>   it_should_behave_like "context 1"
>   it_should_behave_like "context 2"
>   .
>   .
>   it_should_behave_like "context 14"
> end
>
> but then I lose the context info in the output, it just displays one long
> list of examples.
> The alternative is:
>
> describe MyController, "context 1" do
>   it_should_behave_like "context 1"
> end
> describe MyController, "context 2" do
>   it_should_behave_like "context 2"
> end
> .
> .
> describe MyController, "context 14" do
>   it_should_behave_like "context 14"
> end
>
> this way the context info is preserved in the output, but it''s
more work,
> especially across 8 controllers.
>
> another thing is, depending on the model being used, controllers will
> instantiate variables of different names. e.g. in the "dvd"
controller, an
> instance of the Dvd model would be stored in @dvd, whereas in the
"book"
> controller, it would be in @book . using dynamic specs, I can make my
> examples more specific depending on the controller being tested e.g. :
>
> # obj and var passed in as parameters
> it "should load a #{obj.class} object into @#{varname}" do
>   get :show
>   assigns[var_name].should == obj
> end
>
> I could put obj and varname into instance variables in the before() method,
> but they''re only available in the example block, not from the
example title
>
> these are minor complaints really, but as my project grows, they become
more
> of an issue.
>
>
>
> David Chelimsky-2 wrote:
> >
> > On 8/4/07, David Green <justnothing at tiscali.co.uk> wrote:
> >>
> >> I have a lot of controllers with virtually identical functionality
for
> >> most
> >> actions. I''ve been using shared behaviours to DRY things
up a bit, but I
> >> still have to create separate behaviours for each context before I
can
> >> use
> >> the shared behaviours
> >>
> >> what I have now is a generic file which contains all the
behaviours and
> >> examples common to all the controllers, and that file gets loaded
from an
> >> actual controller spec. The generic file knows which controller to
test
> >> by
> >> calling kontroller(), which is defined in the controller spec.
> >>
> >> here''s a very simplified example:
> >> http://pastebin.com/m6b47bae9
> >>
> >> It works great when I run the specs individually, but when I use
rake,
> >> specs
> >> begin to fail and i think it''s because the value of
kontroller() is set
> >> to
> >> whatever it returns the first time it gets called. Here''s
the rake output
> >> from running the specs shown above:
> >>
> >>
> >> FooController
> >> .FooController
> >> .
> >>
> >> Finished in 0.041793 seconds
> >> 2 examples, 0 failures
> >>
> >> I would expect it to print FooController and then BarController
...
> >> interestingly, if I insert ''puts
kontroller.to_s'' *outside* of the
> >> describe
> >> block, then it does output the names of both controllers as
expected.
> >>
> >> does anyone know of a solution?
> >> thanks
> >>
> >> dave
> >
> > I''m all for keeping things DRY, but NEVER at the risk of
clarity.
> > You''ve got to balance DRY and readability/clarity. Anybody
familiar
> > with rspec can look at this:
> >
> > ========================> > describe FooController do
> >   it_should_behave_like "All Controllers"
> > end
> > ========================> >
> > and understand what that means: A FooController should behave like All
> > Controllers. Perhaps there is a split second of mental mapping:
"Oh,
> > there must be some behaviour described for all controllers that the
> > FooController should adopt."
> >
> > Compare that to your example:
> >
> > ========================> > def kontroller
> >   FooController
> > end
> >
> > load File.dirname(__FILE__) + ''/all_controllers.rb''
> > ========================> >
> > First of all - how is that any more DRY than the example above?
> > Perhaps you save a few keystrokes, but if you think that makes it more
> > DRY then you don''t really understand what DRY is all about.
> >
> > Second of all, what does it actually mean? Where''s the story?
How is a
> > non-developer going to look at that and have any context for what that
> > means? I''m a developer and I don''t know what it
means. Sure I can
> > figure it out, but, in my opinion, it''s just nowhere near as
clear as
> > the example above.
> >
> > FWIW,
> > David
> > _______________________________________________
> > rspec-users mailing list
> > rspec-users at rubyforge.org
> > http://rubyforge.org/mailman/listinfo/rspec-users
> >
> >
>
> --
> View this message in context:
http://www.nabble.com/reusable-specs---almost-there-tf4216708.html#a12007548
> Sent from the rspec-users mailing list archive at Nabble.com.