[rspec-users] shared behav

Scott Taylor mailing_lists at railsnewbie.com
Tue Dec 18 17:45:11 EST 2007


On Dec 18, 2007, at 5:31 PM, David Chelimsky wrote:

> On Dec 18, 2007 4:25 PM, David Chelimsky <dchelimsky at gmail.com> wrote:
>>
>> On Dec 18, 2007 4:22 PM, Scott Taylor  
>> <mailing_lists at railsnewbie.com> wrote:
>>>
>>>
>>> On Dec 18, 2007, at 5:12 PM, David Chelimsky wrote:
>>>
>>>> On Dec 18, 2007 3:53 PM, Scott Taylor
>>>> <mailing_lists at railsnewbie.com> wrote:
>>>>>
>>>>>
>>>>> On Dec 18, 2007, at 4:42 PM, David Chelimsky wrote:
>>>>>
>>>>>> On Dec 18, 2007 3:37 PM, Scott Taylor
>>>>>> <mailing_lists at railsnewbie.com> wrote:
>>>>>>> The
>>>>>>> shared behaviours can be thought of modules which are included
>>>>>>> into the
>>>>>>> current behaviour - so it should also have access to any methods
>>>>>>> defined in
>>>>>>> the example (group) in which it is shared.
>>>>>>
>>>>>> You don't even have to think of it that way - that's actually  
>>>>>> what
>>>>>> they are - modules that get included. You can actually assign
>>>>>> them to
>>>>>> a constant and just use Ruby include.
>>>>>
>>>>> Although we've talked about the implementation changing, which  
>>>>> would
>>>>> cause those who use them as modules to have broken specs.
>>>>
>>>> It would, but we stopped talking about it :)
>>>>
>>>> It actually works quite well this way. The change came up, iirc, in
>>>> the conversation about parameterizing it_should_behave_like, right?
>>>> I've got a solution for that worked out, but I haven't applied  
>>>> it yet
>>>> because I want to discuss it a bit:
>>>>
>>>> You'd use it like this:
>>>>
>>>> shared_examples_for "anything" do
>>>>   it "should do stuff" do
>>>>     @thing.should do_stuff
>>>>   end
>>>> end
>>>>
>>>> describe SpecificThing do
>>>>   it_should_behave_like "anything", :thing => SpecificThing.new
>>>> end
>>>>
>>>> Now comes the tricky part. This can work one of two ways. In either
>>>> case it turns :thing into an instance variable @thing. The  
>>>> question is
>>>> whether that instance variable is assigned in the scope of the
>>>> SpecificThing example group or in a scope created especially to run
>>>> the shared examples. Each choice presents usability confusion in my
>>>> view.
>>>>
>>>> Imagine this scenario:
>>>>
>>>> shared_examples_for "anything" do
>>>>   it "should do stuff" do
>>>>     @thing.should do_stuff
>>>>   end
>>>>   it "should be like another thing" do
>>>>     @thing.should be_like(@other_thing)
>>>>   end
>>>> end
>>>>
>>>> describe SpecificThing do
>>>>   before(:each) do
>>>>     @thing = SpecificThing.new
>>>>   end
>>>>   it_should_behave_like "anything", :other_thing =>  
>>>> SpecificThing.new
>>>>
>>>>   it "should not be unlike other thing" do
>>>>     @thing.should_not be_unlike(@other_thing)
>>>>   end
>>>> end
>>>>
>>>> If @other_thing is defined in the context of a separate scope  
>>>> just to
>>>> run the shared examples, the shared examples won't know about  
>>>> @thing.
>>>>
>>>> If @other_thing in the scope of the example group created by  
>>>> "describe
>>>> SpecificThing," then it's just confusing to look at - both
>>>> before(:each) and it_should_behave_like are creating instance
>>>> variables in the current scope, and it is NOT clear that is what is
>>>> happening.
>>>>
>>>> If we go w/ the separate scope, then the metaphor of
>>>> it_should_behave_like is wrong, because we're not talking about
>>>> something in the current scope that should behave like something  
>>>> else
>>>> anymore. We'd probably want a different construct to create these,
>>>> even though the underlying mechanism would be the same.
>>>>
>>>> Thoughts?
>>>
>>>
>>> How about this:
>>>
>>> Use a separate scope, but copy the instance variables from the
>>> calling example group.  Any parameters passed into the shared  
>>> example
>>> group will be methods which wrap the values given.   This way we
>>> don't have instance variable naming conflicts (like @other_thing, in
>>> the example above).
>>>
>>> On the other hand, this would also mean that shared example groups
>>> wouldn't have the ability to call methods in the calling example  
>>> group.
>>>
>>> Thoughts?
>>
>> Copying instance variables around is nasty business. In fact, we
>> eliminated that from shared behaviours by making them modules that  
>> get
>> included! So I would view that as a step backwards from an
>> implementation standpoint, and it still feels like voodoo from a
>> usability standpoint.
>
> Well - THAT was nothing but negative.
>
> Let me add some positive to balance things:
>
> As I think about it, I'm more inclined to make this a completely
> different method, as I suggested as an option earlier. Something that
> says "run in another scope with these variables." That way there's no
> magic and consequently no confusion.

I'm with you on that one.  I don't like "it_should_behave_like" much  
anyway - I end up aliasing it in a few different forms:

it_should_behave_like_a
it_should_behave_like_the

and so on.

Anyway - how do the nested behaviours work right now?  Are instance  
variables being copied?  Methods?

Scott



More information about the rspec-users mailing list