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 <[EMAIL PROTECTED]> wrote:
>> On 8/23/07, Daniel N <[EMAIL PROTECTED]> wrote:
>>>
>>>
>>>
>>> On 8/24/07, Courtenay <[EMAIL PROTECTED]> wrote:
>>>> Does this work?
>>>>
>>>> Image.stub!(:validates_uniqueness_of).and_return(true)
>>>>
>>>>
>>>> On 8/23/07, s.ross <[EMAIL PROTECTED]> 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
> [email protected]
> http://rubyforge.org/mailman/listinfo/rspec-users
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users