[rspec-users] a better "should have valid associations"

Craig Demyanovich cdemyanovich at gmail.com
Thu Mar 29 11:30:59 EDT 2007


On Mar 29, 2007, at 11:05 AM, David Chelimsky wrote:

> On 3/29/07, Craig Demyanovich <cdemyanovich at gmail.com> wrote:
>> On Mar 29, 2007, at 10:22 AM, Bryan Helmkamp wrote:
>>
>>> On 3/29/07, Courtenay <court3nay at gmail.com> wrote:
>>>> Thanks to Wilson for converting to the new form. I've added a few
>>>> lines.
>>>
>>> Actually, I converted this to the matcher syntax. Wilson and I are
>>> using it on a project we are working on together.
>>>
>>> While have_valid_associations is useful as a safety net in places
>>> where you are otherwise uncovered, I now strongly prefer enumerating
>>> the associations that should exist in the spec. To do that, we  
>>> use the
>>> following code:
>>>
>>> ==========================================
>>>
>>>   class HaveAssociation
>>>     def initialize(association_name)
>>>       @association_name = association_name
>>>     end
>>>
>>>     def matches?(model)
>>>       @model_class = model.class
>>>       success = true
>>>       model.send(@association_name.to_sym, true) rescue success =
>>> false
>>>       success
>>>     end
>>>
>>>     def failure_message
>>>       "invalid or nonexistent association \"#{@association_name} 
>>> \" on
>>> #{@model_class}"
>>>     end
>>>   end
>>>
>>>   def have_association(association_name)
>>>     HaveAssociation.new(association_name)
>>>   end
>>>
>>> ==========================================
>>>
>>> And then in the model spec (we include ActiveRecordMatchers in the
>>> context for all model specs):
>>>
>>> context "A car" do
>>>   setup do
>>>     @car = Car.new
>>>   end
>>>
>>>   specify "should have valid associations" do
>>>     @car.should have_association(:owner)
>>>     @car.should have_association(:insurance)
>>>   end
>>> end
>>>
>>> Now we're covered in the case that an association is accidentally
>>> removed. The "should have valid associations" specification can  
>>> get a
>>> big long and ugly on more complex classes, so we often use this
>>> syntax:
>>>
>>> context "A car" do
>>>   setup do
>>>     @car = Car.new
>>>   end
>>>
>>>   %w[owner insurance driver passengers engine].each do |assoc|
>>>     specify "should have valid #{assoc} association" do
>>>       @car.should have_association(assoc)
>>>     end
>>>   end
>>>
>>> This has the added bonus of producing much better specdoc:
>>>
>>> A car
>>> - should have valid owner association
>>> - should have valid insurance association
>>> - should have valid driver association
>>> - should have valid passengers association
>>> - should have valid engine association
>>>
>>> -Bryan
>>
>> Nice idea, Bryan. It doesn't go far enough for me, though: it
>> verifies only the name of the association. I want to verify that I've
>> specified the correct macro (e.g., :has_many instead of :has_one),
>> class and foreign key. Part of why I want this is because I'm working
>> with a legacy database that doesn't follow the Rails conventions at
>> all. In addition, though, checking all of the association attributes
>> increases my confidence that I'll notice if something about the
>> association changes or if I make a mistake defining it, such as
>> using :has_one instead of :has_many. For these reasons, I'm doing
>> what I posted earlier in this thread. Thoughts?
>
> How about this?
>
> project.should belong_to(:manager)
> manager.should have_many(:projects)
>
> etc
>
> This would involve more matchers, but could be implemented in the same
> fashion as have_association is above.

That looks pretty good, David. In fact, it's probably just right for  
apps that use a database that follows the Rails conventions. However,  
does anyone have any ideas for how we could specify the class and  
foreign key? I feel that I need to specify those as well since my  
database is quite unconventional according to Rails. Change may be in  
its future, but it's not safe just yet.

Thanks,
Craig


More information about the rspec-users mailing list