[rspec-users] get to a different controller

Matt Wynne matt at mattwynne.net
Thu Jan 7 05:09:35 EST 2010


On 7 Jan 2010, at 07:22, Wincent Colaiuta wrote:

> El 07/01/2010, a las 03:53, Phillip Koebbe escribió:
>
>> Wincent Colaiuta wrote:
>>>
>>> Well, there is more than one way to skin a cat, but the thing I  
>>> like about my proposed solution is that:
>>>
>>> - the specification of the behavior appears in the "describe"  
>>> block that corresponds to the controller where the behavior is  
>>> implemented
>>>
>>> - but given that the implementing controller is an abstract one,  
>>> you actually test the behavior where it is actually exercised (ie.  
>>> in the subclasses)
>>>
>>> - you don't need to make a fictional controller which isn't  
>>> actually part of your application purely for testing purposes
>>>
>>> Looking at the gist you pasted it looks like it could be very  
>>> straightforward to test, especially if you're using a RESTful  
>>> access pattern.
>>>
>>> Your admin controllers all inherit from your abstract base class,  
>>> and if they're RESTful you know before you even start which  
>>> actions they'll respond to (the usual index, new, create etc).  
>>> Perhaps they only respond to a subset; but even if they only  
>>> respond to one ("show" or "index", say) you have enough of a  
>>> common basis to test that the require_admin before filter is  
>>> actually hit and does what you think it should (ie. you only need  
>>> to hit "show" or "index", there is no need to test all actions).
>>>
>>> Cheers,
>>> Wincent
>>>
>>
>> Are you basically saying that you wouldn't worry about testing the  
>> before_filter in the base_controller at all?
>
> Exactly. The base_controller is never directly instantiated and its  
> "behaviour" is only ever manifested in the context of its  
> subclasses, so you can test the behavior by testing that it exists  
> in the subclasses.
>
> As you have seen, you can't really test the abstract base_controller  
> directly itself because it has no actions.
>
>> Maybe part of the reason I am not "getting this" is my lack of  
>> familiarity with shared behaviors. If I share the behavior in the  
>> base_controller_spec, will it get tested when I run that spec? If  
>> it won't, then my concern is moot. If it will, then I'm just as  
>> confused as I was before.
>
> Shared behaviors are just a convenient way to define in behaviors  
> once in a single place, which will be exercised in multiple places,  
> so that you can keep things DRY.
>
> If you run the file with the "describe foo :shared => true" block in  
> it, nothing will actually happen.
>
> Your assertions get exercised only when you run other "describe"  
> blocks containing "it_should_behave_like ..."
>
> They can be useful not just in cases like this where you have an  
> abstract superclass. You can use them wherever you have a bunch of  
> common behavior across different classes.

OK I'm going to bite on this one.

Shared behaviours are indeed useful and a really nice idea. When I  
first started working with RSpec I used them exactly like this - I  
wrote no specs for abstract classes or modules, and wrote shared  
behaviour specs which I mixed in to all the classes that used the  
abstract class or module. I told myself: "this is much better - I'm  
not being distracted by the implementation details (inheritance,  
mixins) I'm just specifying the behaviour of the class".

I think that method probably works great for small models, but I have  
found that over time on the Songkick codebase, I've come to rather  
dislike the shared behaviours. This is mainly, I think, because when I  
get a failure, the error message doesn't point me very clearly at  
which class was actually being tested when the failure occurred. I  
also think I resent them because I know that for a popular module, I  
might be running the exact same specs over the exact same code several  
times, for no purpose.

What I now prefer to do is keep the interface between a module (or  
even an abstract class) and the class it's mixed into quite clean, and  
specify that re-usable unit in isolation, with an example using a  
temporary class created in the test. I might have one or two specs in  
the class which mixes in the module to prove that the module is mixed  
in and working, but most of the specs for the behaviour of that module  
itself will live alongside the module and run only once.

As David said earlier there are strengths and weaknesses to both  
approaches so you have to find your own path here. I just wanted to  
share my experience.

cheers,
Matt

http://mattwynne.net
+447974 430184



More information about the rspec-users mailing list