[rspec-users] controller spec with model that validates_uniqueness

s.ross cwdinfo at gmail.com
Thu Aug 23 23:13:08 EDT 2007


I left out a key piece of my spec code in the original question:

   before(:each) do
     @category = mock_model(Category)
     Category.should_receive(:find).any_number_of_times.and_return 
(@category)
     @image = mock_model(Image)
     @image_category = mock_model(ImageCategory)
   end

For this simple controller (and they are *all* supposed to be simple,  
right?), I think taking AR out completely might work.

It's all working now... Thanks for all responses.

BTW: Courtenay, great that you're using rSpec on the Caboose Sample App.


On Aug 23, 2007, at 7:57 PM, Zach Dennis wrote:

> Actually better then an exception
>
> On 8/23/07, Zach Dennis <zach.dennis at gmail.com> wrote:
>> On 8/23/07, Daniel N <has.sox at gmail.com> wrote:
>>>
>>>
>>>
>>> On 8/24/07, Courtenay <court3nay at gmail.com> wrote:
>>>> Does this work?
>>>>
>>>>    Image.stub!(:validates_uniqueness_of).and_return(true)
>>>>
>>>>
>>>> On 8/23/07, s.ross <cwdinfo at gmail.com> wrote:
>>>>> I want to use mocks and stubs to test the controller, but am  
>>>>> having
>>>>> trouble getting my validation not to trigger. Here's the code:
>>>>>
>>>>> # spec:
>>>>>
>>>>>      Image.stub!(:find).and_return(@image)
>>>>>      @image.should_receive(:save!).once.with(:any_args)
>>>>>      put :update, :id => @image.id, :category_id =>
>>>>> @category.id, :image => {:name => 'test', :image_number => 13554}
>>>>>
>>>>> #model
>>>>>
>>>>>    validates_presence_of :name
>>>>>    validates_uniqueness_of :name, :allow_nil => true
>>>>>
>>>>> # rspec output
>>>>>
>>>>> ActiveRecord::RecordInvalid in 'ImagesController should update a
>>>>> database record when it receives a PUT'
>>>>> Validation failed: Name has already been taken, Image number has
>>>>> already been taken
>>>>>
>>>>>
>>>>> It seems AR is not detecting that this is an edit/update that will
>>>>> not cause a uniqueness conflict. I believe the code in the model
>>>>> needs to remain in place because I don't want a user creating a  
>>>>> name
>>>>> conflict by editing an existing name into one that already  
>>>>> exists in
>>>>> the database. Any thoughts on how better to spec this?
>>>>>
>>>>> Thanks
>>>>> _______________________________________________
>>>
>>>  Why use a real image at all?  I usually use mock_model on these  
>>> and then
>>> stub/mock the specific calls in the controller method.  This way  
>>> your not
>>> testing the model at all.  Just the controller.  Of course, they  
>>> can get
>>> pretty complex with all the stubbing etc.
>>>
>>>      Image.stub!(:find).and_return(@image)
>>>      @image.should_receive(:save!).once.with(:any_args)
>>>      put :update, :id => @image.id, :category_id =>
>>>  @category.id, :image => {:name => 'test', :image_number => 13554}
>>>
>>>  could become.
>>>
>>>  @category = mock_model( Category, :id => 1 ) # Not sure where  
>>> this one is
>>> used other than the call to put
>>>  @image = mock_model( Image, :id => 2 )
>>>  @image.should_receive( :save! ).once.with( :any_args ).and_return 
>>> ( true )
>>>  Image.stub!( :find ).and_return( @image )
>>>
>>>  put :update, :id => @image.id, :category_id =>
>>>  @category.id, :image => {:name => 'test', :image_number => 13554}
>>>
>>>  This way you're not reaching into the model to check your  
>>> controller.
>>
>> You can even go as far as removing all of that ActiveRecord
>> interaction from your controller.
>>
>>   @image = mock("image")
>>   Image.should_receive(:update_image).with(@image)
>>   put :update, :id => 1, :category_id => 2, :image => @image
>>
>> You would also want to test a failure case I'm sure (if you  
>> redirected...):
>>
>>    Image.stub!(:update_image).and_raise 
>> (ActiveRecord::ActiveRecordError)
>>    put :update, :id => 1, :category_id => 2, :image => @image
>>    response.should be_redirect
>>    response.should redirect_to(:action => "other_action")
>>
>> This keeps your controller a little cleaner and pushes down the
>> interaction of working with ActiveRecord models to a minimum. Now you
>> can put the code that actually handles an update in your model class
>> and your controller doesn't have to worry about how it is saved, it
>> either works or raises an exception,
>
> If you are only using Category in the test then go with Daniel's first
> suggestion. If you only need a numeric id which represents a Category
> don't create a dummy mock that will only be used in your test.
>
> If your controller has to find a Category and an Image to update an
> image in your controller then I think my approach (minus the
> exception, use true/false return values instead on update_image) makes
> sense.
>
> Zach
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users



More information about the rspec-users mailing list