[rspec-users] reusable specs - almost there

David Green
Thu, 09 Aug 2007 11:07:31 -0000

David Chelimsky-2 wrote:
>
> 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.
>
> Interesting. This is kind of backwards from how I envision shared
> behaviours. To me, a shared behaviour is a behaviour that is shared
> across objects, not contexts. In other words:
>
> describe "any controller", :shared => true do
>   it "should do a when b" { ... }
> end
>
> describe "a specific controller" do
>   it_should_behave_like "any controller"
> end
>
> As opposed to:
>
> describe "any controller when the user is logged in", :shared
=> true do
>   it "should do a when b" { ... }
> end
>
> describe "a specific controller" do
>   it_should_behave_like "any controller when the user is logged
in"
> end
>
> Subtle difference, but I''m sure it guides in a different
direction.
>
> The problem you''re experiencing is not new, and I''m
definitely
> interested in discussing solutions for it, but I''m much more
> interested in ways rspec could improve than ways to work around
> rspec''s deficiencies.
>
>> 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.
>
> Understood - although, if all of these controllers are behaving
> exactly the same way with only a variable name or two difference, it
> seems to me that the duplication problem is in the code, not the
> specs. Perhaps there is some common code that could be extracted to a
> module - then you can have specs for that module and specify that the
> module should be included in each of your controllers.
>
> WDYT?
>
>

I spent some time refactoring and I''m at happy with the stage
I''m at now. as
per your suggestion, I extracted common code and now only test it in one
controller. In situations where it isn''t practical to extract code,
I''m
still using shared behaviour but setting instance variables in before() to
customize the specs slightly.

I''ve pretty much given up on dynamically generating specs. as for
improving
rspec, I think it would be a great feature if shared behaviours could accept
parameters, which are available both inside and outside examples. Then you
could do things like:

describe "a standard create action", :shared => true do

  it "should instantiate a new #{target_class} object called
#{target_name}"
do
    get :create
    assigns[target_name].should be_instance_of(target_class)
  end

end

I can accomplish the same by setting @target_name and @target_class instance
variables, but it would be nice if the example titles could include those
values too.

thanks for all your help
dave
--
View this message in context: