Suppose a "User" has many "widgets", and that we have a method in the User class that does something like: def update_widgets x = ... code to do some calculations ... if x > 5 new_widget = widgets.new new_widget.save! else widgets.first.destroy end widgets.reload end How would one spec this without having to worry about the validations for new_widget? Is there any way in the spec to tell it to replace instances of save! with instances of save(false) or something along those lines? Using message expectations is difficult in this case because the new_widget doesn't exist before the method is called, so there's not object that can ahead of time expect to receive the save! method. Thanks..
on 2009-05-11 18:12
on 2009-05-11 19:57
On 11 May 2009, at 17:05, Barun Singh wrote: > end > receive the save! method. If you have a user object in your specs, you could do this: user.widgets.stub!(:new).and_return(mock(Widget, :save! => nil)) but you're getting into some ugly territory mixing mocks with calls to the database (e.g. widgets.reload). What does your spec look like? Matt Wynne http://blog.mattwynne.net http://www.songkick.com
on 2009-05-11 20:25
Yes, that mixture of mocking and database calls is what was giving me a lot of headache. And with my actual code more than one object might be created in the method so stubbing out the :new method would have added a lot of complication to my specs if I were to maintain good coverage. I tried using Widget.any_instance.stub!(:valid?).and_return(false) but this didn't work for me (doing a google search reveals that perhaps I'd have to apply some sort of patch to get this functionality, which I am not so keen on doing). For now I've overcome this problem by just writing my specs in such a way that I ensure that new_widget is a valid object. Some of the attributes assigned to new_widget before it is saved are dependent upon objects and fields that I am mocking or stubbing in my specs. I was using oversimplified mocks, thinking I should be able to avoid dealing with validation since that is tested elsewhere already. But, not having found a way to do that I am now using more realistic mocks so that the new_widget.save! method does not raise an error anymore.
on 2009-05-12 03:15
On Mon, May 11, 2009 at 12:05 PM, Barun Singh <email@example.com> wrote: > end > > widgets.reload > end > > How would one spec this without having to worry about the validations for > new_widget? It seems pretty important that update_widgets is able to produce actual widgets. I would use actual models here rather than try to stub/mock something out. After all the whole method is about creating (or destroying) the widgets. It seems pretty central to the behaviour of the method. However, if what you shared is the "dumbed" down version of your code for us on the ML then perhaps there is something complicated going on that makes it a good candidate to be designed differently. > Is there any way in the spec to tell it to replace instances of > save! with instances of save(false) or something along those lines? Using > message expectations is difficult in this case because the new_widget > doesn't exist before the method is called, so there's not object that can > ahead of time expect to receive the save! method. Are you telling us the full story? In the above code you shared you don't pass any attributes into "widget.new". So, how does it create valid widgets in the actual app? > > Thanks.. > > _______________________________________________ > rspec-users mailing list > firstname.lastname@example.org > http://rubyforge.org/mailman/listinfo/rspec-users > -- Zach Dennis http://www.continuousthinking.com (personal) http://www.mutuallyhuman.com (hire me) @zachdennis (twitter)