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 > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users