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