Tarsoly András
2007-Oct-26 10:55 UTC
[rspec-users] specing rescue, ensure and else blocks of an Exception
Greetings, I''m using rspec with rcov for my applications and there is one issue which I cannot solve nor can find any proper information regarding it: specing what is in a rescue block in case of an exception. I''m using Ruby on Rails and I usually make use of exceptions in my controllers, like the following example: def action @foo = Foo.find(1) @foo.update_attributes!(params[:foo]) redirect_to :back rescue ActiveRecord::RecordInvalid => e ...exception handling code ... rescue Exception => e ...exception handling code ... else ...else block ensure ...ensure block end I have a specs for this, like this one: it "should retrieve a Foo instance, identified by ID and update it''s parameters" do Foo.should_receive(:find).with("1").and_return(@foo) @foo.should_receive(:update_attributes!).with (valid_params).and_return(@foo) get :action, :id => 1 response.should be_redirect end it "should retrieve a Foo instance, identified by ID and throw an exception, because of bad parameters" do Foo.should_receive(:find).with("1").and_return(@foo) @foo.should_receive(:update_attributes!).with (valid_params).and_return(@foo) get :action, :id => 1 response.should raise_error end or it "should retrieve a Foo instance, identified by ID and throw an exception, because of bad parameters" do Foo.should_receive(:find).with("1").and_return(@foo) lambda { @foo.should_receive(:update_attributes!).with (valid_params).and_return(@foo) }.should raise_error get :action, :id => 1 end ... and ... that''s it, the tests pass, becaue an Exception is raised, but I don''t know how to proceed with testing all the rescue, ensure and else blocks. Since rcov reporting it as not being run, my coverage is suffering and I really don''t want to release code which are only being partially tested. So any pointers, help or links to some quick rundown regarding this problem would be greatly appreciated. Thanks a bunch and my best regards, Andr?s -- Tarsoly Andr?s tarsolya at gmail.com -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20071026/bfb8b197/attachment-0001.html
Ashley Moran
2007-Oct-26 11:56 UTC
[rspec-users] specing rescue, ensure and else blocks of an Exception
On 26 Oct 2007, at 11:55, Tarsoly Andr?s wrote:> So any pointers, help or links to some quick rundown regarding this > problem would be greatly appreciated.From a brief look over (apologies if I missed something), you are not invoking the errors you need to cause your rescue etc blocks to run. I think you want to do: @foo.should_receive(:update_attributes!).with(params [:foo]).and_raise(RecordNotSaved) @object_in_rescue_block.should_receive(:some_message) get :action, :id => 1 What you appear to be doing here:> it "should retrieve a Foo instance, identified by ID and throw an > exception, because of bad parameters" do > Foo.should_receive(:find).with("1").and_return(@foo) > lambda { @foo.should_receive(:update_attributes!).with > (valid_params).and_return(@foo) }.should raise_error > get :action, :id => 1 > endis testing that the code throws an exception, NOT that your code handles it; ie you are describing an assumption of someone else''s code rather than the behaviour of yours, which is not what you want in a spec. Ashley -- blog @ http://aviewfromafar.net/ linked-in @ http://www.linkedin.com/in/ashleymoran currently @ work
David Chelimsky
2007-Oct-26 11:56 UTC
[rspec-users] specing rescue, ensure and else blocks of an Exception
On 10/26/07, Tarsoly Andr?s <tarsolya at gmail.com> wrote:> Greetings, > > I''m using rspec with rcov for my applications and there is one issue which I > cannot solve nor can find any proper information regarding it: specing what > is in a rescue block in case of an exception. > > I''m using Ruby on Rails and I usually make use of exceptions in my > controllers, like the following example: > > def action > @foo = Foo.find(1) > @foo.update_attributes!(params[:foo]) > redirect_to :back > rescue ActiveRecord::RecordInvalid => e > ...exception handling code ... > rescue Exception => e > ...exception handling code ... > else > ...else block > ensure > ...ensure block > end > > I have a specs for this, like this one: > > it "should retrieve a Foo instance, identified by ID and update it''s > parameters" do > Foo.should_receive(:find).with("1").and_return(@foo) > > @foo.should_receive(:update_attributes!).with(valid_params).and_return(@foo) > get :action, :id => 1 > response.should be_redirect > end > > it "should retrieve a Foo instance, identified by ID and throw an exception, > because of bad parameters" do > Foo.should_receive(:find).with("1").and_return(@foo) > > @foo.should_receive(:update_attributes!).with(valid_params).and_return(@foo) > get :action, :id => 1 > response.should raise_error > end > > or > > > it "should retrieve a Foo instance, identified by ID and throw an exception, > because of bad parameters" do > Foo.should_receive(:find).with("1").and_return(@foo) > lambda { > @foo.should_receive(:update_attributes!).with(valid_params).and_return(@foo) > }.should raise_error > get :action, :id => 1 > endThere are a few problems with these examples. First of all, they use "get" when they should use "post", so they''re likely not executing the right stuff. Next, they are describing expected model behaviour in your controller spec. What we''re interested in here is not that the model raises an error under certain conditions - that''s something we should spec in model specs - we''re interested in what the controller does when the model raises an error. Lastly, the examples have AND in them. That should be a red flag. Each example should describe a single aspect of the behaviour of the action when invoked under specific circumstances. Take a look at http://pastie.caboo.se/111125 (reorganized from your example). Note that each example is about what the controller does, not what the model does. Also note that there are no "and"s in any of the labels. Each example sets up one thing and describes what happens when the action is invoked based on those conditions. HTH, David> > ... and ... that''s it, the tests pass, becaue an Exception is raised, but I > don''t know how to proceed with testing all the rescue, ensure and else > blocks. Since rcov reporting it as not being run, my coverage is suffering > and I really don''t want to release code which are only being partially > tested.
Ashley Moran
2007-Oct-26 12:00 UTC
[rspec-users] specing rescue, ensure and else blocks of an Exception
On 26 Oct 2007, at 12:56, Ashley Moran wrote:> @foo.should_receive(:update_attributes!).with(params > [:foo]).and_raise(RecordNotSaved)Sorry, RecordInvalid.new in your case, not RecordNotSaved (with or without the new) -- blog @ http://aviewfromafar.net/ linked-in @ http://www.linkedin.com/in/ashleymoran currently @ work
David Chelimsky
2007-Oct-26 12:02 UTC
[rspec-users] specing rescue, ensure and else blocks of an Exception
On 10/26/07, David Chelimsky <dchelimsky at gmail.com> wrote:> On 10/26/07, Tarsoly Andr?s <tarsolya at gmail.com> wrote: > Take a look at http://pastie.caboo.se/111125 (reorganized from your > example). Note that each example is about what the controller does, > not what the model does. Also note that there are no "and"s in any of > the labels. Each example sets up one thing and describes what happens > when the action is invoked based on those conditions. > > HTH, > DavidHere''s an alternative broken down into more granular specs: http://pastie.caboo.se/111130. Generally I find that I don''t break up my controller specs like that, but I break up specs for models like that all the time, so maybe I should be doing them this way :)
Tarsoly András
2007-Oct-26 13:29 UTC
[rspec-users] specing rescue, ensure and else blocks of an Exception
Thanks a lot guys, this is great help, it''s really appreciated, it makes a lot more sense now. I somehow felt that I''m not entirely on the right path when I''m doing controller testing, and your replies and examples given here shed some light on it. David, I like your alternative better, since it has more structure. Also, I''d like to ask one more question, which popped into my mind after reviewing these examples, but it''s not relating strictly into the previous topic. Is there some way, to say something like: it "should" do post :any_action, params end I''m using some before filters in my controllers to DRY up my code, for example: retrieve a specific record, if params[:id] is set. This is very useful for automatic scoping and assigning instance vars in some controllers, which are relate to nested resources (eg. map.resources :foo, has_many => [:bar]) The aim of this would be to DRY up the tests a little bit, since each action always retrieves a specific set of records, and I could spec it out in the shared model for all possible actions at once, or I am missing something here either? :) Thanks again for the great examples, regards: Andr?s On 2007.10.26., at 14:02, David Chelimsky wrote:> On 10/26/07, David Chelimsky <dchelimsky at gmail.com> wrote: >> On 10/26/07, Tarsoly Andr?s <tarsolya at gmail.com> wrote: >> Take a look at http://pastie.caboo.se/111125 (reorganized from your >> example). Note that each example is about what the controller does, >> not what the model does. Also note that there are no "and"s in any of >> the labels. Each example sets up one thing and describes what happens >> when the action is invoked based on those conditions. >> >> HTH, >> David > > Here''s an alternative broken down into more granular specs: > http://pastie.caboo.se/111130. > > Generally I find that I don''t break up my controller specs like that, > but I break up specs for models like that all the time, so maybe I > should be doing them this way :) > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users-- Tarsoly Andr?s tarsolya at gmail.com