Hello, I''m wondering If I am missing something here when creating an example that sets an expecation at the top or beginning of an action but requires you to stub / mock everything that follows. Example: I want to test that a certain controller is running a before_filter...thats easy: - controller.should_receive(:require_user) - do_get But now i''ve got to mock / stub everything else that comes behind this filter so that I don''t receive ''unexpected method'' errors, or other blowups because I am requesting the whole action. Is there anyway to stop execution after an expectation has been met? It seems to me that this might clean things up a bit. Not sure, I''m still fairly new to BDD/Mocking by about 2 weeks. Thanks _________________________________________________________________ Need to know now? Get instant answers with Windows Live Messenger. http://www.windowslive.com/messenger/connect_your_way.html?ocid=TXT_TAGLM_WL_Refresh_messenger_062008
On Sat, Jun 28, 2008 at 5:57 PM, Britt Mileshosky <mileshosky at hotmail.com> wrote:> > Hello, I''m wondering If I am missing something here when creating an example that sets an expecation at the top or beginning of an action but requires you to stub / mock everything that follows. > > Example: > I want to test that a certain controller is running a before_filter...thats easy: > > - controller.should_receive(:require_user) > - do_get > > But now i''ve got to mock / stub everything else that comes behind this filter so that I don''t receive ''unexpected method'' errors, or other blowups because I am requesting the whole action. Is there anyway to stop execution after an expectation has been met? It seems to me that this might clean things up a bit. Not sure, I''m still fairly new to BDD/Mocking by about 2 weeks.Yep, you can stub out the requested action on the controller. Say you''re testing that the :index action requires authentication: controller.should_not_receive(:index) stub_not_logged_in do_get Or the opposite: controller.should_receive(:index) stub_logged_in do_get Personally I prefer expecting the action instead of expecting the filters, but I think both would accomplish the same goal, as long as you tested the filter on its own. If you just wanted to stub out the action to prevent it from doing anything, you could of course just use controller.stub!(:index). HTH k
----------------------------------------> Date: Sat, 28 Jun 2008 18:24:17 -0500 > From: philodespotos at gmail.com > To: rspec-users at rubyforge.org > Subject: Re: [rspec-users] Stopping example execution? > > On Sat, Jun 28, 2008 at 5:57 PM, Britt Mileshosky > wrote: >> >> Hello, I''m wondering If I am missing something here when creating an example that sets an expecation at the top or beginning of an action but requires you to stub / mock everything that follows. >> >> Example: >> I want to test that a certain controller is running a before_filter...thats easy: >> >> - controller.should_receive(:require_user) >> - do_get >> >> But now i''ve got to mock / stub everything else that comes behind this filter so that I don''t receive ''unexpected method'' errors, or other blowups because I am requesting the whole action. Is there anyway to stop execution after an expectation has been met? It seems to me that this might clean things up a bit. Not sure, I''m still fairly new to BDD/Mocking by about 2 weeks. > > Yep, you can stub out the requested action on the controller. Say > you''re testing that the :index action requires authentication: > > controller.should_not_receive(:index) > stub_not_logged_in > do_get > > Or the opposite: > > controller.should_receive(:index) > stub_logged_in > do_get > > Personally I prefer expecting the action instead of expecting the > filters, but I think both would accomplish the same goal, as long as > you tested the filter on its own. If you just wanted to stub out the > action to prevent it from doing anything, you could of course just use > controller.stub!(:index). > > HTH > > k > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-usersSo i did something like. - controller.should_receive(:before_filter_action) - controller.stub!(:action_after_filter) - do_get Works nicely... but if you think about it and look closely, we are still stubbing methods after the intended expectation was met. This method just happens to encapsulate a whole other set of methods, which is why it works nicely. But lets say i have something like this --------------------------------------------------------------------------------------------------- def some_action @user = self.current_user @account = self.current_account if self.has_account? @person = @account.people.find(params[:person]) end --------------------------------------------------------------------------------------------------- describe "with a logged in user" before(:each) do controller.stub!(:current_account) @account = stub_model(UserAccount) # Shouldn''t have to stub here? @person = stub_model(User) # Shouldn''t have to stub here? @people = mock("list of people") # Shouldn''t have to stub here? @people.stub!(find) # Shouldn''t have to stub here? @account.stub!(:people).and_return(@people) # Shouldn''t have to stub here? end it "should find current user" do controller.should_receive(:current_user).and_return(@mockUser) do_get end describe "who has an account" do ... should put account stubbing here with examples describe "which has people" do ... should put people stubbing here with examples end describe "which has 0 people" do ... end end describe "who doesnt have an account" do ... end end ------------------------------------------------------------------------------------------------------------------------------ Notice I have to stub everything out at the first before(:each) declaration because my "should find current user" example will blow up because of unexpected methods after the expectation. All I want to know is that the current user is expected to be found and stop. My examples LATER should define stubs and expectations. I''d like something like - controller.should_receive(:current_user).and_return(@mockUser).end_example Am i going about it all wrong? Is there something I''m missing or does this just seem natural... Gracias, Britt _________________________________________________________________ Earn cashback on your purchases with Live Search - the search that pays you back! http://search.live.com/cashback/?&pkw=form=MIJAAF/publ=HMTGL/crea=earncashback
On Jun 28, 2008, at 8:27 PM, Britt Mileshosky wrote:> > > ---------------------------------------- >> Date: Sat, 28 Jun 2008 18:24:17 -0500 >> From: philodespotos at gmail.com >> To: rspec-users at rubyforge.org >> Subject: Re: [rspec-users] Stopping example execution? >> >> On Sat, Jun 28, 2008 at 5:57 PM, Britt Mileshosky >> wrote: >>> >>> Hello, I''m wondering If I am missing something here when creating >>> an example that sets an expecation at the top or beginning of an >>> action but requires you to stub / mock everything that follows. >>> >>> Example: >>> I want to test that a certain controller is running a >>> before_filter...thats easy: >>> >>> - controller.should_receive(:require_user) >>> - do_get >>> >>> But now i''ve got to mock / stub everything else that comes behind >>> this filter so that I don''t receive ''unexpected method'' errors, or >>> other blowups because I am requesting the whole action. Is there >>> anyway to stop execution after an expectation has been met? It >>> seems to me that this might clean things up a bit. Not sure, I''m >>> still fairly new to BDD/Mocking by about 2 weeks. >> >> Yep, you can stub out the requested action on the controller. Say >> you''re testing that the :index action requires authentication: >> >> controller.should_not_receive(:index) >> stub_not_logged_in >> do_get >> >> Or the opposite: >> >> controller.should_receive(:index) >> stub_logged_in >> do_get >> >> Personally I prefer expecting the action instead of expecting the >> filters, but I think both would accomplish the same goal, as long as >> you tested the filter on its own. If you just wanted to stub out the >> action to prevent it from doing anything, you could of course just >> use >> controller.stub!(:index). >> >> HTH >> >> k >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users > > > So i did something like. > > - controller.should_receive(:before_filter_action) > - controller.stub!(:action_after_filter) > - do_get > > Works nicely... but if you think about it and look closely, we are > still stubbing methods after the intended expectation was met. This > method just happens to encapsulate a whole other set of methods, > which is why it works nicely. > > But lets say i have something like this > > --------------------------------------------------------------------------------------------------- > > def some_action > @user = self.current_user > @account = self.current_account if self.has_account? > @person = @account.people.find(params[:person]) > end > > --------------------------------------------------------------------------------------------------- > > describe "with a logged in user" > > before(:each) do > controller.stub!(:current_account) > @account = stub_model(UserAccount) # Shouldn''t have to stub here? > @person = stub_model(User) # Shouldn''t have to stub > here? > @people = mock("list of people") # Shouldn''t have to stub > here? > @people.stub!(find) # Shouldn''t have > to stub here? > @account.stub!(:people).and_return(@people) # Shouldn''t > have to stub here? > endAre you looking for the :null_object => true flag? Scott
----------------------------------------> From: mailing_lists at railsnewbie.com > To: rspec-users at rubyforge.org > Date: Sat, 28 Jun 2008 20:32:26 -0400 > Subject: Re: [rspec-users] Stopping example execution? > > > On Jun 28, 2008, at 8:27 PM, Britt Mileshosky wrote: > >> >> >> ---------------------------------------- >>> Date: Sat, 28 Jun 2008 18:24:17 -0500 >>> From: philodespotos at gmail.com >>> To: rspec-users at rubyforge.org >>> Subject: Re: [rspec-users] Stopping example execution? >>> >>> On Sat, Jun 28, 2008 at 5:57 PM, Britt Mileshosky >>> wrote: >>>> >>>> Hello, I''m wondering If I am missing something here when creating >>>> an example that sets an expecation at the top or beginning of an >>>> action but requires you to stub / mock everything that follows. >>>> >>>> Example: >>>> I want to test that a certain controller is running a >>>> before_filter...thats easy: >>>> >>>> - controller.should_receive(:require_user) >>>> - do_get >>>> >>>> But now i''ve got to mock / stub everything else that comes behind >>>> this filter so that I don''t receive ''unexpected method'' errors, or >>>> other blowups because I am requesting the whole action. Is there >>>> anyway to stop execution after an expectation has been met? It >>>> seems to me that this might clean things up a bit. Not sure, I''m >>>> still fairly new to BDD/Mocking by about 2 weeks. >>> >>> Yep, you can stub out the requested action on the controller. Say >>> you''re testing that the :index action requires authentication: >>> >>> controller.should_not_receive(:index) >>> stub_not_logged_in >>> do_get >>> >>> Or the opposite: >>> >>> controller.should_receive(:index) >>> stub_logged_in >>> do_get >>> >>> Personally I prefer expecting the action instead of expecting the >>> filters, but I think both would accomplish the same goal, as long as >>> you tested the filter on its own. If you just wanted to stub out the >>> action to prevent it from doing anything, you could of course just >>> use >>> controller.stub!(:index). >>> >>> HTH >>> >>> k >>> _______________________________________________ >>> rspec-users mailing list >>> rspec-users at rubyforge.org >>> http://rubyforge.org/mailman/listinfo/rspec-users >> >> >> So i did something like. >> >> - controller.should_receive(:before_filter_action) >> - controller.stub!(:action_after_filter) >> - do_get >> >> Works nicely... but if you think about it and look closely, we are >> still stubbing methods after the intended expectation was met. This >> method just happens to encapsulate a whole other set of methods, >> which is why it works nicely. >> >> But lets say i have something like this >> >> --------------------------------------------------------------------------------------------------- >> >> def some_action >> @user = self.current_user >> @account = self.current_account if self.has_account? >> @person = @account.people.find(params[:person]) >> end >> >> --------------------------------------------------------------------------------------------------- >> >> describe "with a logged in user" >> >> before(:each) do >> controller.stub!(:current_account) >> @account = stub_model(UserAccount) # Shouldn''t have to stub here? >> @person = stub_model(User) # Shouldn''t have to stub >> here? >> @people = mock("list of people") # Shouldn''t have to stub >> here? >> @people.stub!(find) # Shouldn''t have >> to stub here? >> @account.stub!(:people).and_return(@people) # Shouldn''t >> have to stub here? >> end > > > > Are you looking for the :null_object => true flag? > > Scott >Scott, I don''t believe so, but can you see where that might work in the example given above? I''ve never used the null_object flag, and looking at the documentation, it seems as though I''d still need to declare all my mocks at the very beginning, rather than incrementally as I work down through my code and examples. _________________________________________________________________ The i?m Talkathon starts 6/24/08.? For now, give amongst yourselves. http://www.imtalkathon.com?source=TXT_EML_WLH_LearnMore_GiveAmongst
----------------------------------------> From: mileshosky at hotmail.com > To: rspec-users at rubyforge.org > Date: Sat, 28 Jun 2008 17:50:19 -0700 > Subject: Re: [rspec-users] Stopping example execution? > > > > ---------------------------------------- >> From: mailing_lists at railsnewbie.com >> To: rspec-users at rubyforge.org >> Date: Sat, 28 Jun 2008 20:32:26 -0400 >> Subject: Re: [rspec-users] Stopping example execution? >> >> >> On Jun 28, 2008, at 8:27 PM, Britt Mileshosky wrote: >> >>> >>> >>> ---------------------------------------- >>>> Date: Sat, 28 Jun 2008 18:24:17 -0500 >>>> From: philodespotos at gmail.com >>>> To: rspec-users at rubyforge.org >>>> Subject: Re: [rspec-users] Stopping example execution? >>>> >>>> On Sat, Jun 28, 2008 at 5:57 PM, Britt Mileshosky >>>> wrote: >>>>> >>>>> Hello, I''m wondering If I am missing something here when creating >>>>> an example that sets an expecation at the top or beginning of an >>>>> action but requires you to stub / mock everything that follows. >>>>> >>>>> Example: >>>>> I want to test that a certain controller is running a >>>>> before_filter...thats easy: >>>>> >>>>> - controller.should_receive(:require_user) >>>>> - do_get >>>>> >>>>> But now i''ve got to mock / stub everything else that comes behind >>>>> this filter so that I don''t receive ''unexpected method'' errors, or >>>>> other blowups because I am requesting the whole action. Is there >>>>> anyway to stop execution after an expectation has been met? It >>>>> seems to me that this might clean things up a bit. Not sure, I''m >>>>> still fairly new to BDD/Mocking by about 2 weeks. >>>> >>>> Yep, you can stub out the requested action on the controller. Say >>>> you''re testing that the :index action requires authentication: >>>> >>>> controller.should_not_receive(:index) >>>> stub_not_logged_in >>>> do_get >>>> >>>> Or the opposite: >>>> >>>> controller.should_receive(:index) >>>> stub_logged_in >>>> do_get >>>> >>>> Personally I prefer expecting the action instead of expecting the >>>> filters, but I think both would accomplish the same goal, as long as >>>> you tested the filter on its own. If you just wanted to stub out the >>>> action to prevent it from doing anything, you could of course just >>>> use >>>> controller.stub!(:index). >>>> >>>> HTH >>>> >>>> k >>>> _______________________________________________ >>>> rspec-users mailing list >>>> rspec-users at rubyforge.org >>>> http://rubyforge.org/mailman/listinfo/rspec-users >>> >>> >>> So i did something like. >>> >>> - controller.should_receive(:before_filter_action) >>> - controller.stub!(:action_after_filter) >>> - do_get >>> >>> Works nicely... but if you think about it and look closely, we are >>> still stubbing methods after the intended expectation was met. This >>> method just happens to encapsulate a whole other set of methods, >>> which is why it works nicely. >>> >>> But lets say i have something like this >>> >>> --------------------------------------------------------------------------------------------------- >>> >>> def some_action >>> @user = self.current_user >>> @account = self.current_account if self.has_account? >>> @person = @account.people.find(params[:person]) >>> end >>> >>> --------------------------------------------------------------------------------------------------- >>> >>> describe "with a logged in user" >>> >>> before(:each) do >>> controller.stub!(:current_account) >>> @account = stub_model(UserAccount) # Shouldn''t have to stub here? >>> @person = stub_model(User) # Shouldn''t have to stub >>> here? >>> @people = mock("list of people") # Shouldn''t have to stub >>> here? >>> @people.stub!(find) # Shouldn''t have >>> to stub here? >>> @account.stub!(:people).and_return(@people) # Shouldn''t >>> have to stub here? >>> end >> >> >> >> Are you looking for the :null_object => true flag? >> >> Scott >> > > Scott, I don''t believe so, but can you see where that might work in the example given above? I''ve never used the null_object flag, and looking at the documentation, it seems as though I''d still need to declare all my mocks at the very beginning, rather than incrementally as I work down through my code and examples. >I just noticed, Scott truncated my email so the full example I gave is not shown above, please refer to the previous messages for my full example. _________________________________________________________________ Earn cashback on your purchases with Live Search - the search that pays you back! http://search.live.com/cashback/?&pkw=form=MIJAAF/publ=HMTGL/crea=earncashback
On Jun 28, 2008, at 7:27 PM, Britt Mileshosky wrote:> ---------------------------------------- >> Date: Sat, 28 Jun 2008 18:24:17 -0500 >> From: philodespotos at gmail.com >> To: rspec-users at rubyforge.org >> Subject: Re: [rspec-users] Stopping example execution? >> >> On Sat, Jun 28, 2008 at 5:57 PM, Britt Mileshosky >> wrote: >>> >>> Hello, I''m wondering If I am missing something here when creating >>> an example that sets an expecation at the top or beginning of an >>> action but requires you to stub / mock everything that follows. >>> >>> Example: >>> I want to test that a certain controller is running a >>> before_filter...thats easy: >>> >>> - controller.should_receive(:require_user) >>> - do_get >>> >>> But now i''ve got to mock / stub everything else that comes behind >>> this filter so that I don''t receive ''unexpected method'' errors, or >>> other blowups because I am requesting the whole action. Is there >>> anyway to stop execution after an expectation has been met? It >>> seems to me that this might clean things up a bit. Not sure, I''m >>> still fairly new to BDD/Mocking by about 2 weeks. >> >> Yep, you can stub out the requested action on the controller. Say >> you''re testing that the :index action requires authentication: >> >> controller.should_not_receive(:index) >> stub_not_logged_in >> do_get >> >> Or the opposite: >> >> controller.should_receive(:index) >> stub_logged_in >> do_get >> >> Personally I prefer expecting the action instead of expecting the >> filters, but I think both would accomplish the same goal, as long as >> you tested the filter on its own. If you just wanted to stub out the >> action to prevent it from doing anything, you could of course just >> use >> controller.stub!(:index). >> >> HTH >> >> k >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users > > > So i did something like. > > - controller.should_receive(:before_filter_action) > - controller.stub!(:action_after_filter) > - do_get > > Works nicely... but if you think about it and look closely, we are > still stubbing methods after the intended expectation was met. This > method just happens to encapsulate a whole other set of methods, > which is why it works nicely. > > But lets say i have something like this > > --------------------------------------------------------------------------------------------------- > > def some_action > @user = self.current_user > @account = self.current_account if self.has_account? > @person = @account.people.find(params[:person]) > end > > --------------------------------------------------------------------------------------------------- > > describe "with a logged in user" > > before(:each) do > controller.stub!(:current_account) > @account = stub_model(UserAccount) # Shouldn''t have to stub here? > @person = stub_model(User) # Shouldn''t have to stub > here? > @people = mock("list of people") # Shouldn''t have to stub > here? > @people.stub!(find) # Shouldn''t have > to stub here? > @account.stub!(:people).and_return(@people) # Shouldn''t > have to stub here? > end > > it "should find current user" do > controller.should_receive(:current_user).and_return(@mockUser) > do_get > end > > describe "who has an account" do > ... should put account stubbing here with examples > > > describe "which has people" do > ... should put people stubbing here with examples > end > > describe "which has 0 people" do > ... > end > > > end > > describe "who doesnt have an account" do > ... > end > > end > > ------------------------------------------------------------------------------------------------------------------------------ > > Notice I have to stub everything out at the first before(:each) > declaration because my "should find current user" example will blow > up because of unexpected methods after the expectation. All I want > to know is that the current user is expected to be found and stop. > My examples LATER should define stubs and expectations. > > I''d like something like > > - > controller > .should_receive(:current_user).and_return(@mockUser).end_example > > Am i going about it all wrong? Is there something I''m missing or > does this just seem natural...You''re doing the right thing by handling the stubs before(:each) - that''s what it''s therefore - to set up the environment so things will run. I would recommend avoiding instance variable assignment there, however. If you need a variable, create it directly in the example. This is something that I''ve only recently started doing and I find that it keeps things much more clear. There are a few things you can do to tidy up the stubs a bit. You could organize things differently to express the relationships better: before(:each) do controller.stub!(:current_user).and_return(stub_model(User)) controller.stub!(:has_account?).and_return(true) controller.stub!(:current_account).and_return( stub_model(UserAccount, :people => stub(''people'', :find => stub_model(Person) ) ) ) end If you wrap self.people.find in self.find_person in Account (which fixes the Law of Demeter violation), like this: def some_action @user = self.current_user @account = self.current_account if self.has_account? @person = @account.find_person(params[:person]) end ... you can reduce the before to this: before(:each) do controller.stub!(:current_user).and_return(stub_model(User)) controller.stub!(:has_account?).and_return(true) controller.stub!(:current_account).and_return( stub_model(UserAccount, :find_person => stub_model(Person) ) ) end In cases like current_user, you don''t really need to stub that because the controller will just return nil. If has_account? actually checks for current_account.nil?, then you don''t have to stub that either. Now you just have this: before(:each) do controller.stub!(:current_account).and_return( stub_model(UserAccount, :find_person => stub_model(Person) ) ) end This is a *bit* more organized, but still quite busy. In the end, when you''re dealing with code that violates Tell, Don''t Ask (which is quite natural in Rails controllers), you have to stub a lot of stuff to get the isolation you want. It''s a tradeoff. HTH, David
----------------------------------------> From: dchelimsky at gmail.com > To: rspec-users at rubyforge.org > Date: Sun, 29 Jun 2008 06:09:47 -0500 > Subject: Re: [rspec-users] Stopping example execution? > > On Jun 28, 2008, at 7:27 PM, Britt Mileshosky wrote: > >> ---------------------------------------- >>> Date: Sat, 28 Jun 2008 18:24:17 -0500 >>> From: philodespotos at gmail.com >>> To: rspec-users at rubyforge.org >>> Subject: Re: [rspec-users] Stopping example execution? >>> >>> On Sat, Jun 28, 2008 at 5:57 PM, Britt Mileshosky >>> wrote: >>>> >>>> Hello, I''m wondering If I am missing something here when creating >>>> an example that sets an expecation at the top or beginning of an >>>> action but requires you to stub / mock everything that follows. >>>> >>>> Example: >>>> I want to test that a certain controller is running a >>>> before_filter...thats easy: >>>> >>>> - controller.should_receive(:require_user) >>>> - do_get >>>> >>>> But now i''ve got to mock / stub everything else that comes behind >>>> this filter so that I don''t receive ''unexpected method'' errors, or >>>> other blowups because I am requesting the whole action. Is there >>>> anyway to stop execution after an expectation has been met? It >>>> seems to me that this might clean things up a bit. Not sure, I''m >>>> still fairly new to BDD/Mocking by about 2 weeks. >>> >>> Yep, you can stub out the requested action on the controller. Say >>> you''re testing that the :index action requires authentication: >>> >>> controller.should_not_receive(:index) >>> stub_not_logged_in >>> do_get >>> >>> Or the opposite: >>> >>> controller.should_receive(:index) >>> stub_logged_in >>> do_get >>> >>> Personally I prefer expecting the action instead of expecting the >>> filters, but I think both would accomplish the same goal, as long as >>> you tested the filter on its own. If you just wanted to stub out the >>> action to prevent it from doing anything, you could of course just >>> use >>> controller.stub!(:index). >>> >>> HTH >>> >>> k >>> _______________________________________________ >>> rspec-users mailing list >>> rspec-users at rubyforge.org >>> http://rubyforge.org/mailman/listinfo/rspec-users >> >> >> So i did something like. >> >> - controller.should_receive(:before_filter_action) >> - controller.stub!(:action_after_filter) >> - do_get >> >> Works nicely... but if you think about it and look closely, we are >> still stubbing methods after the intended expectation was met. This >> method just happens to encapsulate a whole other set of methods, >> which is why it works nicely. >> >> But lets say i have something like this >> >> --------------------------------------------------------------------------------------------------- >> >> def some_action >> @user = self.current_user >> @account = self.current_account if self.has_account? >> @person = @account.people.find(params[:person]) >> end >> >> --------------------------------------------------------------------------------------------------- >> >> describe "with a logged in user" >> >> before(:each) do >> controller.stub!(:current_account) >> @account = stub_model(UserAccount) # Shouldn''t have to stub here? >> @person = stub_model(User) # Shouldn''t have to stub >> here? >> @people = mock("list of people") # Shouldn''t have to stub >> here? >> @people.stub!(find) # Shouldn''t have >> to stub here? >> @account.stub!(:people).and_return(@people) # Shouldn''t >> have to stub here? >> end >> >> it "should find current user" do >> controller.should_receive(:current_user).and_return(@mockUser) >> do_get >> end >> >> describe "who has an account" do >> ... should put account stubbing here with examples >> >> >> describe "which has people" do >> ... should put people stubbing here with examples >> end >> >> describe "which has 0 people" do >> ... >> end >> >> >> end >> >> describe "who doesnt have an account" do >> ... >> end >> >> end >> >> ------------------------------------------------------------------------------------------------------------------------------ >> >> Notice I have to stub everything out at the first before(:each) >> declaration because my "should find current user" example will blow >> up because of unexpected methods after the expectation. All I want >> to know is that the current user is expected to be found and stop. >> My examples LATER should define stubs and expectations. >> >> I''d like something like >> >> - >> controller >> .should_receive(:current_user).and_return(@mockUser).end_example >> >> Am i going about it all wrong? Is there something I''m missing or >> does this just seem natural... > > > You''re doing the right thing by handling the stubs before(:each) - > that''s what it''s therefore - to set up the environment so things will > run. > > I would recommend avoiding instance variable assignment there, > however. If you need a variable, create it directly in the example. > This is something that I''ve only recently started doing and I find > that it keeps things much more clear. > > There are a few things you can do to tidy up the stubs a bit. You > could organize things differently to express the relationships better: > > before(:each) do > controller.stub!(:current_user).and_return(stub_model(User)) > controller.stub!(:has_account?).and_return(true) > controller.stub!(:current_account).and_return( > stub_model(UserAccount, > :people => stub(''people'', > :find => stub_model(Person) > ) > ) > ) > end > > If you wrap self.people.find in self.find_person in Account (which > fixes the Law of Demeter violation), like this: > > def some_action > @user = self.current_user > @account = self.current_account if self.has_account? > @person = @account.find_person(params[:person]) > end > > ... you can reduce the before to this: > > before(:each) do > controller.stub!(:current_user).and_return(stub_model(User)) > controller.stub!(:has_account?).and_return(true) > controller.stub!(:current_account).and_return( > stub_model(UserAccount, > :find_person => stub_model(Person) > ) > ) > end > > In cases like current_user, you don''t really need to stub that because > the controller will just return nil. > > If has_account? actually checks for current_account.nil?, then you > don''t have to stub that either. Now you just have this: > > before(:each) do > controller.stub!(:current_account).and_return( > stub_model(UserAccount, > :find_person => stub_model(Person) > ) > ) > end > > This is a *bit* more organized, but still quite busy. In the end, when > you''re dealing with code that violates Tell, Don''t Ask (which is quite > natural in Rails controllers), you have to stub a lot of stuff to get > the isolation you want. It''s a tradeoff. > > HTH, > DavidThank you David, that helps quite a bit, I will adapt these principles and move on. However, do you see where something like a return statement or end example statement could be beneficial? If you are working from the top down with your controller action execution, then you only need to test your expectation and then bail out of your action. No need to further test or meet requirements on anything else in that action because your single test has been met. - in my example for making sure I find a user, I''d like to end execution once I DID find the user, i shouldn''t have to satisfy requirements about finding an account and a person... I''ll write those expectations later in another nested describe group, as you can see here, in a top down process PeopleController with a logged in user - should find user PeopleController with a logged in user who has an account - should find account PeopleController with a logged in user who doesnt have an account - shouldn''t find account - should redirect ... PeopleController with a logged in user who has an account the person belongs to - should find person - should assign person for the view PeopleController with a logged in user who has an account the requested person does not belong to - should not find person - should ... _________________________________________________________________ The i?m Talkathon starts 6/24/08.? For now, give amongst yourselves. http://www.imtalkathon.com?source=TXT_EML_WLH_LearnMore_GiveAmongst
On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote:> However, do you see where something like a return statement or end > example statement could be beneficial? > If you are working from the top down with your controller action > execution, then you only need to test your expectation > and then bail out of your action. No need to further test or meet > requirements on anything else in that action because your > single test has been met. > > - in my example for making sure I find a user, I''d like to end > execution once I DID find the user, i shouldn''t have to satisfy > requirements about finding an account and a person... I''ll write > those expectations later in another nested describe group, as you > can see here, in a top down process > > PeopleController with a logged in user > - should find user > > PeopleController with a logged in user who has an account > - should find account > > PeopleController with a logged in user who doesnt have an account > - shouldn''t find account > - should redirect ... > > PeopleController with a logged in user who has an account the person > belongs to > - should find person > - should assign person for the view > > PeopleController with a logged in user who has an account the > requested person does not belong to > - should not find person > - should ...My instinct about this is that it would encourage long methods because it would make it less painful to test them, so I would be adverse to anything that let''s you short circuit the method. Anybody else have opinions on that?
----------------------------------------> From: dchelimsky at gmail.com > To: rspec-users at rubyforge.org > Date: Sun, 29 Jun 2008 11:20:46 -0500 > Subject: Re: [rspec-users] Stopping example execution? > > On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote: >> However, do you see where something like a return statement or end >> example statement could be beneficial? >> If you are working from the top down with your controller action >> execution, then you only need to test your expectation >> and then bail out of your action. No need to further test or meet >> requirements on anything else in that action because your >> single test has been met. >> >> - in my example for making sure I find a user, I''d like to end >> execution once I DID find the user, i shouldn''t have to satisfy >> requirements about finding an account and a person... I''ll write >> those expectations later in another nested describe group, as you >> can see here, in a top down process >> >> PeopleController with a logged in user >> - should find user >> >> PeopleController with a logged in user who has an account >> - should find account >> >> PeopleController with a logged in user who doesnt have an account >> - shouldn''t find account >> - should redirect ... >> >> PeopleController with a logged in user who has an account the person >> belongs to >> - should find person >> - should assign person for the view >> >> PeopleController with a logged in user who has an account the >> requested person does not belong to >> - should not find person >> - should ... > > My instinct about this is that it would encourage long methods because > it would make it less painful to test them, so I would be adverse to > anything that let''s you short circuit the method. > > Anybody else have opinions on that? >I understand your point, but should a testing framework be worried too much about how a user will be writing their application code? Leave it to the programmer to decide what logic they put in the controller, let the testing framework make it easy to test that certain conditions are met, no matter how those conditions are presented in the application. This short-circuting can be completely optional... it would just be nice to have it there if needed. In the end I honestly can see a more natural process to testing methods bit by bit, building up examples and stubs in their respective describe groups as needed. If someone wants to single describe group and all stubs at the top, so be it. I''d like mine to be incrementally built upon each other. I''ll be quiet now and let others discuss, (...I''m cheering for this though!) _________________________________________________________________ Need to know now? Get instant answers with Windows Live Messenger. http://www.windowslive.com/messenger/connect_your_way.html?ocid=TXT_TAGLM_WL_Refresh_messenger_062008
On Jun 29, 2008, at 11:38 AM, Britt Mileshosky wrote:> ---------------------------------------- >> From: dchelimsky at gmail.com >> To: rspec-users at rubyforge.org >> Date: Sun, 29 Jun 2008 11:20:46 -0500 >> Subject: Re: [rspec-users] Stopping example execution? >> >> On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote: >>> However, do you see where something like a return statement or end >>> example statement could be beneficial? >>> If you are working from the top down with your controller action >>> execution, then you only need to test your expectation >>> and then bail out of your action. No need to further test or meet >>> requirements on anything else in that action because your >>> single test has been met. >>> >> My instinct about this is that it would encourage long methods >> because >> it would make it less painful to test them, so I would be adverse to >> anything that let''s you short circuit the method. >> >> Anybody else have opinions on that? >> > > I understand your point, but should a testing framework be worried > too much about how a user will be writing their application code?YES. This is Ruby, my friend, land of opinionated software. The whole point of RSpec is to encourage good practices. Long Methods (any method does more than one thing) are a known Code Smell. If you want to write them, it should be painful. You''re certainly entitled to a different opinion, and you can express that opinion in a gem that extends rspec to do what you want! If you do that and enough people use it and it proves generally useful and pain-free, I''d be glad to peek at it again. Cheers, David> > Leave it to the programmer to decide what logic they put in the > controller, let the testing framework make it easy to test > that certain conditions are met, no matter how those conditions are > presented in the application. > > This short-circuting can be completely optional... it would just be > nice to have it there if needed. In the end I honestly can see a more > natural process to testing methods bit by bit, building up examples > and stubs in their respective describe groups as needed. If someone > wants to single describe group and all stubs at the top, so be it. > I''d like mine to be incrementally built upon each other. > > I''ll be quiet now and let others discuss, (...I''m cheering for this > though!) > > _________________________________________________________________ > Need to know now? Get instant answers with Windows Live Messenger. > http://www.windowslive.com/messenger/connect_your_way.html?ocid=TXT_TAGLM_WL_Refresh_messenger_062008 > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
On Mon, Jun 30, 2008 at 2:59 AM, David Chelimsky <dchelimsky at gmail.com> wrote:> On Jun 29, 2008, at 11:38 AM, Britt Mileshosky wrote: >>> My instinct about this is that it would encourage long methods because >>> it would make it less painful to test them, so I would be adverse to >>> anything that let''s you short circuit the method. >>> >>> Anybody else have opinions on that?I agree with you here David. The long method syndrome is so easy to fall into in ruby and rails especially. Many times I have shown some of my team mates that coding small methods makes specing a lot easier and containable. Another way to go about this testing is to treat the controller method as a public interface and only spec the ''end result'' behaviour with a given set of inputs using real objects (which has limits, but works in most cases). Britt, have a look at http://lindsaar.net/2008/6/30/examples-of-behaviour-spec-n to see what I mean. Doesn''t totally solve the problem you are hitting now, but provides you with another way to go about it (albeit a bit slower in spec execution time) -- http://lindsaar.net/ Rails, RSpec, Puppet and Life blog....
On Sun, Jun 29, 2008 at 12:20 PM, David Chelimsky <dchelimsky at gmail.com> wrote:> On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote: > >> However, do you see where something like a return statement or end example >> statement could be beneficial? >> If you are working from the top down with your controller action >> execution, then you only need to test your expectation >> and then bail out of your action. No need to further test or meet >> requirements on anything else in that action because your >> single test has been met. >> >> - in my example for making sure I find a user, I''d like to end execution >> once I DID find the user, i shouldn''t have to satisfy >> requirements about finding an account and a person... I''ll write those >> expectations later in another nested describe group, as you >> can see here, in a top down process >> >> PeopleController with a logged in user >> - should find user >> >> PeopleController with a logged in user who has an account >> - should find account >> >> PeopleController with a logged in user who doesnt have an account >> - shouldn''t find account >> - should redirect ... >> >> PeopleController with a logged in user who has an account the person >> belongs to >> - should find person >> - should assign person for the view >> >> PeopleController with a logged in user who has an account the requested >> person does not belong to >> - should not find person >> - should ... >> > > My instinct about this is that it would encourage long methods because it > would make it less painful to test them, so I would be adverse to anything > that let''s you short circuit the method. > > Anybody else have opinions on that?I''m just catching up on email now after being sick for the past six days, but health aside my opinion is that I agree with David''s opinion. Rather than focusing on how-to write easier tests that complain less, start focusing on how-to write the right tests that complain when necessary. One of the benefits associated with feeling the pain of a test is that it may be a sign to re-assess and refactor your code. This usually happens early enough that it only takes a few minutes. Short circuiting essentially gives you the ability to not feel the pain. Its like CIPA [0], but for code. I would fear that the code would get so bad that by the time the test cried with pain your code was already beyond easy repair and instead required invasive surgery. Tests are part of the nervous system of your application. When they hurt, they''re telling you something isn''t right and that it should be addressed, 0 - http://en.wikipedia.org/wiki/Congenital_insensitivity_to_pain_with_anhidrosis -- Zach Dennis http://www.continuousthinking.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20080630/0ae5e849/attachment.html>
n Sun, Jun 29, 2008 at 12:20 PM, David Chelimsky wrote: On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote: However, do you see where something like a return statement or end example statement could be beneficial? If you are working from the top down with your controller action execution, then you only need to test your expectation and then bail out of your action. No need to further test or meet requirements on anything else in that action because your single test has been met. - in my example for making sure I find a user, I''d like to end execution once I DID find the user, i shouldn''t have to satisfy requirements about finding an account and a person... I''ll write those expectations later in another nested describe group, as you can see here, in a top down process PeopleController with a logged in user - should find user PeopleController with a logged in user who has an account - should find account PeopleController with a logged in user who doesnt have an account - shouldn''t find account - should redirect ... PeopleController with a logged in user who has an account the person belongs to - should find person - should assign person for the view PeopleController with a logged in user who has an account the requested person does not belong to - should not find person - should ... My instinct about this is that it would encourage long methods because it would make it less painful to test them, so I would be adverse to anything that let''s you short circuit the method. Anybody else have opinions on that? I''m just catching up on email now after being sick for the past six days, but health aside my opinion is that I agree with David''s opinion. Rather than focusing on how-to write easier tests that complain less, start focusing on how-to write the right tests that complain when necessary. One of the benefits associated with feeling the pain of a test is that it may be a sign to re-assess and refactor your code. This usually happens early enough that it only takes a few minutes. Short circuiting essentially gives you the ability to not feel the pain. Its like CIPA [0], but for code. I would fear that the code would get so bad that by the time the test cried with pain your code was already beyond easy repair and instead required invasive surgery. Tests are part of the nervous system of your application. When they hurt, they''re telling you something isn''t right and that it should be addressed, I wouldn''t really say that anything I have been presenting has been a result of ''pains'', more so an observation on how an example group with other example groups can be much more readable for myself and for other developers when they need to read the specs. Stubbing everything at the top doesn''t make complete sense. Why not stub inside the example group that has a NICE describe statement telling you what this stubbing is related to. We can''t do this because the first examples will blow up due to having to execute all the code. Take the 2 examples: ------------------------------------------------------------------------------------------------------------------------ PeopleController # stub everything way up here at the top where these # definitions are out of context (by means of position) with following examples # # stub controller requirments # stub logged in requirement # stub account requirement # stub no account requirement # stub account owns person # stub account doesn''t own person PeopleController with before filters - should require user PeopleController with a logged in user - should find user PeopleController with a logged in user who has an account - should find account PeopleController with a logged in user who doesnt have an account - shouldn''t find account - should redirect ... PeopleController with a logged in user who has an account the person belongs to - should find person - should assign person for the view PeopleController with a logged in user who has an account the requested person does not belong to - should not find person - should ... ------------------------------------------------------------------------------------------------------------------------ PeopleController # stub the minimum needed to get to the first example group up and running PeopleController with before filters - should require user PeopleController with a logged in user # stub logged in requirement - should find user PeopleController with a logged in user who has an account # stub account requirement - should find account PeopleController with a logged in user who doesnt have an account # stub no account requirement - shouldn''t find account - should redirect ... PeopleController with a logged in user who has an account the person belongs to # stub account owns person - should find person - should assign person for the view PeopleController with a logged in user who has an account the requested person does not belong to # stub account doesn''t own person - should not find person - should ... ------------------------------------------------------------------------------------------------------------------------ I prefer the second group, but unfortunately I am not able to write my specs in this organized fashion. Just sayin. Britt _________________________________________________________________ Need to know now? Get instant answers with Windows Live Messenger. http://www.windowslive.com/messenger/connect_your_way.html?ocid=TXT_TAGLM_WL_Refresh_messenger_062008
On Mon, Jun 30, 2008 at 5:11 PM, Britt Mileshosky <mileshosky at hotmail.com> wrote:> > n Sun, Jun 29, 2008 at 12:20 PM, David Chelimsky wrote: > On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote: > > However, do you see where something like a return statement or end example statement could be beneficial? > If you are working from the top down with your controller action execution, then you only need to test your expectation > and then bail out of your action. No need to further test or meet requirements on anything else in that action because your > single test has been met. > > - in my example for making sure I find a user, I''d like to end execution once I DID find the user, i shouldn''t have to satisfy > requirements about finding an account and a person... I''ll write those expectations later in another nested describe group, as you > can see here, in a top down process > > PeopleController with a logged in user > - should find user > > PeopleController with a logged in user who has an account > - should find account > > PeopleController with a logged in user who doesnt have an account > - shouldn''t find account > - should redirect ... > > PeopleController with a logged in user who has an account the person belongs to > - should find person > - should assign person for the view > > PeopleController with a logged in user who has an account the requested person does not belong to > - should not find person > - should ... > > My instinct about this is that it would encourage long methods because it would make it less painful to test them, so I would be adverse to anything that let''s you short circuit the method. > > Anybody else have opinions on that? > > > > I''m just catching up on email now after being sick for the past six days, but health aside my opinion is that I agree with David''s opinion. Rather than focusing on how-to write easier tests that complain less, start focusing on how-to write the right tests that complain when necessary. > > One of the benefits associated with feeling the pain of a test is that it may be a sign to re-assess and refactor your code. This usually happens early enough that it only takes a few minutes. Short circuiting essentially gives you the ability to not feel the pain. Its like CIPA [0], but for code. I would fear that the code would get so bad that by the time the test cried with pain your code was already beyond easy repair and instead required invasive surgery. > > Tests are part of the nervous system of your application. When they hurt, they''re telling you something isn''t right and that it should be addressed, > > > > I wouldn''t really say that anything I have been presenting has been a result of ''pains'', > more so an observation on how an example group with other example groups can be much more readable > for myself and for other developers when they need to read the specs. Stubbing everything at the top doesn''t > make complete sense. Why not stub inside the example group that has a NICE describe statement telling you > what this stubbing is related to. We can''t do this because the first examples will blow up due to having to execute > all the code. > > Take the 2 examples: > > ------------------------------------------------------------------------------------------------------------------------ > PeopleController > # stub everything way up here at the top where these > # definitions are out of context (by means of position) with following examples > # > # stub controller requirments > # stub logged in requirement > # stub account requirement > # stub no account requirement > # stub account owns person > # stub account doesn''t own person > > > PeopleController with before filters > - should require user > > PeopleController with a logged in user > - should find user > > PeopleController with a logged in user who has an account > - should find account > > PeopleController with a logged in user who doesnt have an account > - shouldn''t find account > - should redirect ... > > PeopleController with a logged in user who has an account the person belongs to > - should find person > - should assign person for the view > > PeopleController with a logged in user who has an account the requested person does not belong to > - should not find person > - should ... > > ------------------------------------------------------------------------------------------------------------------------ > PeopleController > # stub the minimum needed to get to the first example group up and running > > PeopleController with before filters > - should require user > > PeopleController with a logged in user > # stub logged in requirement > - should find user > > PeopleController with a logged in user who has an account > # stub account requirement > - should find account > > PeopleController with a logged in user who doesnt have an account > # stub no account requirement > - shouldn''t find account > - should redirect ... > > PeopleController with a logged in user who has an account the person belongs to > # stub account owns person > - should find person > - should assign person for the view > > PeopleController with a logged in user who has an account the requested person does not belong to > # stub account doesn''t own person > - should not find person > - should ... > > ------------------------------------------------------------------------------------------------------------------------ > > I prefer the second group, but unfortunately I am not able to write my specs in this organized fashion. > Just sayin.I appreciate the communication value you''re looking for, and you can get it by stubbing everything you need to keep execution going before(:each) example and then set message expectations (should_receive) inside each example that help tell the story of that example. PeopleController # stub everything way up here at the top where these # definitions are out of context (by means of position) with following examples # # stub controller requirments # stub logged in requirement # stub account requirement # stub no account requirement # stub account owns person # stub account doesn''t own person PeopleController with before filters - should require user PeopleController with a logged in user # expect logged in query - should find user PeopleController with a logged in user who has an account # expect logged in query # expect account query - should find account etc HTH, David> > Britt
----------------------------------------> Date: Wed, 2 Jul 2008 06:15:10 -0500 > From: dchelimsky at gmail.com > To: rspec-users at rubyforge.org > Subject: Re: [rspec-users] Stopping Example Execution? > > On Mon, Jun 30, 2008 at 5:11 PM, Britt Mileshosky > wrote: >> >> n Sun, Jun 29, 2008 at 12:20 PM, David Chelimsky wrote: >> On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote: >> >> However, do you see where something like a return statement or end example statement could be beneficial? >> If you are working from the top down with your controller action execution, then you only need to test your expectation >> and then bail out of your action. No need to further test or meet requirements on anything else in that action because your >> single test has been met. >> >> - in my example for making sure I find a user, I''d like to end execution once I DID find the user, i shouldn''t have to satisfy >> requirements about finding an account and a person... I''ll write those expectations later in another nested describe group, as you >> can see here, in a top down process >> >> PeopleController with a logged in user >> - should find user >> >> PeopleController with a logged in user who has an account >> - should find account >> >> PeopleController with a logged in user who doesnt have an account >> - shouldn''t find account >> - should redirect ... >> >> PeopleController with a logged in user who has an account the person belongs to >> - should find person >> - should assign person for the view >> >> PeopleController with a logged in user who has an account the requested person does not belong to >> - should not find person >> - should ... >> >> My instinct about this is that it would encourage long methods because it would make it less painful to test them, so I would be adverse to anything that let''s you short circuit the method. >> >> Anybody else have opinions on that? >> >> >> >> I''m just catching up on email now after being sick for the past six days, but health aside my opinion is that I agree with David''s opinion. Rather than focusing on how-to write easier tests that complain less, start focusing on how-to write the right tests that complain when necessary. >> >> One of the benefits associated with feeling the pain of a test is that it may be a sign to re-assess and refactor your code. This usually happens early enough that it only takes a few minutes. Short circuiting essentially gives you the ability to not feel the pain. Its like CIPA [0], but for code. I would fear that the code would get so bad that by the time the test cried with pain your code was already beyond easy repair and instead required invasive surgery. >> >> Tests are part of the nervous system of your application. When they hurt, they''re telling you something isn''t right and that it should be addressed, >> >> >> >> I wouldn''t really say that anything I have been presenting has been a result of ''pains'', >> more so an observation on how an example group with other example groups can be much more readable >> for myself and for other developers when they need to read the specs. Stubbing everything at the top doesn''t >> make complete sense. Why not stub inside the example group that has a NICE describe statement telling you >> what this stubbing is related to. We can''t do this because the first examples will blow up due to having to execute >> all the code. >> >> Take the 2 examples: >> >> ------------------------------------------------------------------------------------------------------------------------ >> PeopleController >> # stub everything way up here at the top where these >> # definitions are out of context (by means of position) with following examples >> # >> # stub controller requirments >> # stub logged in requirement >> # stub account requirement >> # stub no account requirement >> # stub account owns person >> # stub account doesn''t own person >> >> >> PeopleController with before filters >> - should require user >> >> PeopleController with a logged in user >> - should find user >> >> PeopleController with a logged in user who has an account >> - should find account >> >> PeopleController with a logged in user who doesnt have an account >> - shouldn''t find account >> - should redirect ... >> >> PeopleController with a logged in user who has an account the person belongs to >> - should find person >> - should assign person for the view >> >> PeopleController with a logged in user who has an account the requested person does not belong to >> - should not find person >> - should ... >> >> ------------------------------------------------------------------------------------------------------------------------ >> PeopleController >> # stub the minimum needed to get to the first example group up and running >> >> PeopleController with before filters >> - should require user >> >> PeopleController with a logged in user >> # stub logged in requirement >> - should find user >> >> PeopleController with a logged in user who has an account >> # stub account requirement >> - should find account >> >> PeopleController with a logged in user who doesnt have an account >> # stub no account requirement >> - shouldn''t find account >> - should redirect ... >> >> PeopleController with a logged in user who has an account the person belongs to >> # stub account owns person >> - should find person >> - should assign person for the view >> >> PeopleController with a logged in user who has an account the requested person does not belong to >> # stub account doesn''t own person >> - should not find person >> - should ... >> >> ------------------------------------------------------------------------------------------------------------------------ >> >> I prefer the second group, but unfortunately I am not able to write my specs in this organized fashion. >> Just sayin. > > I appreciate the communication value you''re looking for, and you can > get it by stubbing everything you need to keep execution going > before(:each) example and then set message expectations > (should_receive) inside each example that help tell the story of that > example. > > PeopleController > # stub everything way up here at the top where these > # definitions are out of context (by means of position) with following examples > # > # stub controller requirments > # stub logged in requirement > # stub account requirement > # stub no account requirement > # stub account owns person > # stub account doesn''t own person > > PeopleController with before filters > - should require user > > PeopleController with a logged in user > # expect logged in query > - should find user > > PeopleController with a logged in user who has an account > # expect logged in query > # expect account query > - should find account > > etc > > HTH, > DavidYep, thats exactly what I''ve been practicing, and while its not exactly what I want, it does work nicely. Thank you David _________________________________________________________________ The i?m Talkaton. Can 30-days of conversation change the world? http://www.imtalkathon.com/?source=EML_WLH_Talkathon_ChangeWorld
----------------------------------------> From: mileshosky at hotmail.com > To: rspec-users at rubyforge.org > Date: Wed, 2 Jul 2008 10:13:59 -0700 > Subject: Re: [rspec-users] Stopping Example Execution? > > > > ---------------------------------------- >> Date: Wed, 2 Jul 2008 06:15:10 -0500 >> From: dchelimsky at gmail.com >> To: rspec-users at rubyforge.org >> Subject: Re: [rspec-users] Stopping Example Execution? >> >> On Mon, Jun 30, 2008 at 5:11 PM, Britt Mileshosky >> wrote: >>> >>> n Sun, Jun 29, 2008 at 12:20 PM, David Chelimsky wrote: >>> On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote: >>> >>> However, do you see where something like a return statement or end example statement could be beneficial? >>> If you are working from the top down with your controller action execution, then you only need to test your expectation >>> and then bail out of your action. No need to further test or meet requirements on anything else in that action because your >>> single test has been met. >>> >>> - in my example for making sure I find a user, I''d like to end execution once I DID find the user, i shouldn''t have to satisfy >>> requirements about finding an account and a person... I''ll write those expectations later in another nested describe group, as you >>> can see here, in a top down process >>> >>> PeopleController with a logged in user >>> - should find user >>> >>> PeopleController with a logged in user who has an account >>> - should find account >>> >>> PeopleController with a logged in user who doesnt have an account >>> - shouldn''t find account >>> - should redirect ... >>> >>> PeopleController with a logged in user who has an account the person belongs to >>> - should find person >>> - should assign person for the view >>> >>> PeopleController with a logged in user who has an account the requested person does not belong to >>> - should not find person >>> - should ... >>> >>> My instinct about this is that it would encourage long methods because it would make it less painful to test them, so I would be adverse to anything that let''s you short circuit the method. >>> >>> Anybody else have opinions on that? >>> >>> >>> >>> I''m just catching up on email now after being sick for the past six days, but health aside my opinion is that I agree with David''s opinion. Rather than focusing on how-to write easier tests that complain less, start focusing on how-to write the right tests that complain when necessary. >>> >>> One of the benefits associated with feeling the pain of a test is that it may be a sign to re-assess and refactor your code. This usually happens early enough that it only takes a few minutes. Short circuiting essentially gives you the ability to not feel the pain. Its like CIPA [0], but for code. I would fear that the code would get so bad that by the time the test cried with pain your code was already beyond easy repair and instead required invasive surgery. >>> >>> Tests are part of the nervous system of your application. When they hurt, they''re telling you something isn''t right and that it should be addressed, >>> >>> >>> >>> I wouldn''t really say that anything I have been presenting has been a result of ''pains'', >>> more so an observation on how an example group with other example groups can be much more readable >>> for myself and for other developers when they need to read the specs. Stubbing everything at the top doesn''t >>> make complete sense. Why not stub inside the example group that has a NICE describe statement telling you >>> what this stubbing is related to. We can''t do this because the first examples will blow up due to having to execute >>> all the code. >>> >>> Take the 2 examples: >>> >>> ------------------------------------------------------------------------------------------------------------------------ >>> PeopleController >>> # stub everything way up here at the top where these >>> # definitions are out of context (by means of position) with following examples >>> # >>> # stub controller requirments >>> # stub logged in requirement >>> # stub account requirement >>> # stub no account requirement >>> # stub account owns person >>> # stub account doesn''t own person >>> >>> >>> PeopleController with before filters >>> - should require user >>> >>> PeopleController with a logged in user >>> - should find user >>> >>> PeopleController with a logged in user who has an account >>> - should find account >>> >>> PeopleController with a logged in user who doesnt have an account >>> - shouldn''t find account >>> - should redirect ... >>> >>> PeopleController with a logged in user who has an account the person belongs to >>> - should find person >>> - should assign person for the view >>> >>> PeopleController with a logged in user who has an account the requested person does not belong to >>> - should not find person >>> - should ... >>> >>> ------------------------------------------------------------------------------------------------------------------------ >>> PeopleController >>> # stub the minimum needed to get to the first example group up and running >>> >>> PeopleController with before filters >>> - should require user >>> >>> PeopleController with a logged in user >>> # stub logged in requirement >>> - should find user >>> >>> PeopleController with a logged in user who has an account >>> # stub account requirement >>> - should find account >>> >>> PeopleController with a logged in user who doesnt have an account >>> # stub no account requirement >>> - shouldn''t find account >>> - should redirect ... >>> >>> PeopleController with a logged in user who has an account the person belongs to >>> # stub account owns person >>> - should find person >>> - should assign person for the view >>> >>> PeopleController with a logged in user who has an account the requested person does not belong to >>> # stub account doesn''t own person >>> - should not find person >>> - should ... >>> >>> ------------------------------------------------------------------------------------------------------------------------ >>> >>> I prefer the second group, but unfortunately I am not able to write my specs in this organized fashion. >>> Just sayin. >> >> I appreciate the communication value you''re looking for, and you can >> get it by stubbing everything you need to keep execution going >> before(:each) example and then set message expectations >> (should_receive) inside each example that help tell the story of that >> example. >> >> PeopleController >> # stub everything way up here at the top where these >> # definitions are out of context (by means of position) with following examples >> # >> # stub controller requirments >> # stub logged in requirement >> # stub account requirement >> # stub no account requirement >> # stub account owns person >> # stub account doesn''t own person >> >> PeopleController with before filters >> - should require user >> >> PeopleController with a logged in user >> # expect logged in query >> - should find user >> >> PeopleController with a logged in user who has an account >> # expect logged in query >> # expect account query >> - should find account >> >> etc >> >> HTH, >> David > > Yep, thats exactly what I''ve been practicing, and while its not exactly what I want, it does work nicely. > Thank you DavidI''m gonna make another REALLY strong case for allowing the ability to stop example execution and test code incrementally. I currently have over 1700 examples for the current application I''m working on, and one little line of code that I added in my App controller ( before_filter :set_location ) brought on almost 1100 errors across my tests. Now I know people will say that the requirements weren''t understood at the beginning of the application and that it could have been avoided with better planning... but this isn''t the case. I now have to go into each of my controller tests and add the stub into every before declaration to clear up my errors. Not fun, and could''ve been avoided completely. Britt _________________________________________________________________ Enter the Zune-A-Day Giveaway for your chance to win ? day after day after day http://www.windowslive-hotmail.com/ZuneADay/?locale=en-US&ocid=TXT_TAGLM_Mobile_Zune_V1
On Jul 2, 2008, at 9:58 PM, Britt Mileshosky wrote:> ---------------------------------------- >> From: mileshosky at hotmail.com >> To: rspec-users at rubyforge.org >> Date: Wed, 2 Jul 2008 10:13:59 -0700 >> Subject: Re: [rspec-users] Stopping Example Execution? >> >> >> >> ---------------------------------------- >>> Date: Wed, 2 Jul 2008 06:15:10 -0500 >>> From: dchelimsky at gmail.com >>> To: rspec-users at rubyforge.org >>> Subject: Re: [rspec-users] Stopping Example Execution? >>> >>> On Mon, Jun 30, 2008 at 5:11 PM, Britt Mileshosky >>> wrote: >>>> >>>> n Sun, Jun 29, 2008 at 12:20 PM, David Chelimsky wrote: >>>> On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote: >>>> >>>> However, do you see where something like a return statement or >>>> end example statement could be beneficial? >>>> If you are working from the top down with your controller action >>>> execution, then you only need to test your expectation >>>> and then bail out of your action. No need to further test or meet >>>> requirements on anything else in that action because your >>>> single test has been met. >>>> >>>> - in my example for making sure I find a user, I''d like to end >>>> execution once I DID find the user, i shouldn''t have to satisfy >>>> requirements about finding an account and a person... I''ll write >>>> those expectations later in another nested describe group, as you >>>> can see here, in a top down process >>>> >>>> PeopleController with a logged in user >>>> - should find user >>>> >>>> PeopleController with a logged in user who has an account >>>> - should find account >>>> >>>> PeopleController with a logged in user who doesnt have an account >>>> - shouldn''t find account >>>> - should redirect ... >>>> >>>> PeopleController with a logged in user who has an account the >>>> person belongs to >>>> - should find person >>>> - should assign person for the view >>>> >>>> PeopleController with a logged in user who has an account the >>>> requested person does not belong to >>>> - should not find person >>>> - should ... >>>> >>>> My instinct about this is that it would encourage long methods >>>> because it would make it less painful to test them, so I would be >>>> adverse to anything that let''s you short circuit the method. >>>> >>>> Anybody else have opinions on that? >>>> >>>> >>>> >>>> I''m just catching up on email now after being sick for the past >>>> six days, but health aside my opinion is that I agree with >>>> David''s opinion. Rather than focusing on how-to write easier >>>> tests that complain less, start focusing on how-to write the >>>> right tests that complain when necessary. >>>> >>>> One of the benefits associated with feeling the pain of a test is >>>> that it may be a sign to re-assess and refactor your code. This >>>> usually happens early enough that it only takes a few minutes. >>>> Short circuiting essentially gives you the ability to not feel >>>> the pain. Its like CIPA [0], but for code. I would fear that the >>>> code would get so bad that by the time the test cried with pain >>>> your code was already beyond easy repair and instead required >>>> invasive surgery. >>>> >>>> Tests are part of the nervous system of your application. When >>>> they hurt, they''re telling you something isn''t right and that it >>>> should be addressed, >>>> >>>> >>>> >>>> I wouldn''t really say that anything I have been presenting has >>>> been a result of ''pains'', >>>> more so an observation on how an example group with other example >>>> groups can be much more readable >>>> for myself and for other developers when they need to read the >>>> specs. Stubbing everything at the top doesn''t >>>> make complete sense. Why not stub inside the example group that >>>> has a NICE describe statement telling you >>>> what this stubbing is related to. We can''t do this because the >>>> first examples will blow up due to having to execute >>>> all the code. >>>> >>>> Take the 2 examples: >>>> >>>> ------------------------------------------------------------------------------------------------------------------------ >>>> PeopleController >>>> # stub everything way up here at the top where these >>>> # definitions are out of context (by means of position) with >>>> following examples >>>> # >>>> # stub controller requirments >>>> # stub logged in requirement >>>> # stub account requirement >>>> # stub no account requirement >>>> # stub account owns person >>>> # stub account doesn''t own person >>>> >>>> >>>> PeopleController with before filters >>>> - should require user >>>> >>>> PeopleController with a logged in user >>>> - should find user >>>> >>>> PeopleController with a logged in user who has an account >>>> - should find account >>>> >>>> PeopleController with a logged in user who doesnt have an account >>>> - shouldn''t find account >>>> - should redirect ... >>>> >>>> PeopleController with a logged in user who has an account the >>>> person belongs to >>>> - should find person >>>> - should assign person for the view >>>> >>>> PeopleController with a logged in user who has an account the >>>> requested person does not belong to >>>> - should not find person >>>> - should ... >>>> >>>> ------------------------------------------------------------------------------------------------------------------------ >>>> PeopleController >>>> # stub the minimum needed to get to the first example group up >>>> and running >>>> >>>> PeopleController with before filters >>>> - should require user >>>> >>>> PeopleController with a logged in user >>>> # stub logged in requirement >>>> - should find user >>>> >>>> PeopleController with a logged in user who has an account >>>> # stub account requirement >>>> - should find account >>>> >>>> PeopleController with a logged in user who doesnt have an account >>>> # stub no account requirement >>>> - shouldn''t find account >>>> - should redirect ... >>>> >>>> PeopleController with a logged in user who has an account the >>>> person belongs to >>>> # stub account owns person >>>> - should find person >>>> - should assign person for the view >>>> >>>> PeopleController with a logged in user who has an account the >>>> requested person does not belong to >>>> # stub account doesn''t own person >>>> - should not find person >>>> - should ... >>>> >>>> ------------------------------------------------------------------------------------------------------------------------ >>>> >>>> I prefer the second group, but unfortunately I am not able to >>>> write my specs in this organized fashion. >>>> Just sayin. >>> >>> I appreciate the communication value you''re looking for, and you can >>> get it by stubbing everything you need to keep execution going >>> before(:each) example and then set message expectations >>> (should_receive) inside each example that help tell the story of >>> that >>> example. >>> >>> PeopleController >>> # stub everything way up here at the top where these >>> # definitions are out of context (by means of position) with >>> following examples >>> # >>> # stub controller requirments >>> # stub logged in requirement >>> # stub account requirement >>> # stub no account requirement >>> # stub account owns person >>> # stub account doesn''t own person >>> >>> PeopleController with before filters >>> - should require user >>> >>> PeopleController with a logged in user >>> # expect logged in query >>> - should find user >>> >>> PeopleController with a logged in user who has an account >>> # expect logged in query >>> # expect account query >>> - should find account >>> >>> etc >>> >>> HTH, >>> David >> >> Yep, thats exactly what I''ve been practicing, and while its not >> exactly what I want, it does work nicely. >> Thank you David > > > I''m gonna make another REALLY strong case for allowing the ability > to stop example execution and test code incrementally. I currently > have over 1700 examples for the current application I''m working on, > and one little line of code that I added in my App controller > ( before_filter :set_location ) brought on almost 1100 errors across > my tests. Now I know people will say that the requirements weren''t > understood at the beginning of the application and that it could > have been avoided with better planning...RSpec < BDD < Agile < Embrace Change. I don''t think you''d see that argument here.> but this isn''t the case. > > I now have to go into each of my controller tests and add the stub > into every before declaration to clear up my errors. Not fun, and > could''ve been avoided completely.Yes, it could have, with the existing tools! Try this next time: Spec::Runner.configure do |config| config.before(:each, :type => :controller) do controller.stub!(:set_location) if controller.respond_to? (:set_location) end end Hey Britt - I appreciate your passion for this feature, but I have to say that I''m as passionately against it as you are for it, for reasons I''ve cited and others have echoed. That said, this is open source. If you want to make this happen then you have a few options. You can write your own gem that extends rspec to do it. You can even fork rspec and add it to your fork, though I think we''d all be better served if you did it in a separate gem. In either case, that would get you the feature you want and give other people a chance to try it out. And if it evolves into an essential feature that a lot of people find real value in, I''d be willing to look at it again. But until such time as its proven itself otherwise, this feature seems more potentially harmful than useful to me. FWIW, David
One good way (IMO) to approach before filters is to always stub them when it comes time to testing a controller action. And to test the filter separately in isolation. For example if you need to define an application level before filter in ApplicationController, then test the filter in isolation using an application_controller_spec. If you''d like to know that your controllers which subclass ApplicationController use them, you can easily add a declarative style "it" helper which verifies that the filter is being used, but doesn''t test the filter (since you already did that in your application_controller_spec. I know this doesn''t help you now, but it is a useful technique which you can use in the future to limit the maintenance nightmare that can come along with things like before filters, Zach On Wed, Jul 2, 2008 at 10:58 PM, Britt Mileshosky <mileshosky at hotmail.com> wrote:> > > ---------------------------------------- > > From: mileshosky at hotmail.com > > To: rspec-users at rubyforge.org > > Date: Wed, 2 Jul 2008 10:13:59 -0700 > > Subject: Re: [rspec-users] Stopping Example Execution? > > > > > > > > ---------------------------------------- > >> Date: Wed, 2 Jul 2008 06:15:10 -0500 > >> From: dchelimsky at gmail.com > >> To: rspec-users at rubyforge.org > >> Subject: Re: [rspec-users] Stopping Example Execution? > >> > >> On Mon, Jun 30, 2008 at 5:11 PM, Britt Mileshosky > >> wrote: > >>> > >>> n Sun, Jun 29, 2008 at 12:20 PM, David Chelimsky wrote: > >>> On Jun 29, 2008, at 11:18 AM, Britt Mileshosky wrote: > >>> > >>> However, do you see where something like a return statement or end > example statement could be beneficial? > >>> If you are working from the top down with your controller action > execution, then you only need to test your expectation > >>> and then bail out of your action. No need to further test or meet > requirements on anything else in that action because your > >>> single test has been met. > >>> > >>> - in my example for making sure I find a user, I''d like to end > execution once I DID find the user, i shouldn''t have to satisfy > >>> requirements about finding an account and a person... I''ll write those > expectations later in another nested describe group, as you > >>> can see here, in a top down process > >>> > >>> PeopleController with a logged in user > >>> - should find user > >>> > >>> PeopleController with a logged in user who has an account > >>> - should find account > >>> > >>> PeopleController with a logged in user who doesnt have an account > >>> - shouldn''t find account > >>> - should redirect ... > >>> > >>> PeopleController with a logged in user who has an account the person > belongs to > >>> - should find person > >>> - should assign person for the view > >>> > >>> PeopleController with a logged in user who has an account the requested > person does not belong to > >>> - should not find person > >>> - should ... > >>> > >>> My instinct about this is that it would encourage long methods because > it would make it less painful to test them, so I would be adverse to > anything that let''s you short circuit the method. > >>> > >>> Anybody else have opinions on that? > >>> > >>> > >>> > >>> I''m just catching up on email now after being sick for the past six > days, but health aside my opinion is that I agree with David''s opinion. > Rather than focusing on how-to write easier tests that complain less, start > focusing on how-to write the right tests that complain when necessary. > >>> > >>> One of the benefits associated with feeling the pain of a test is that > it may be a sign to re-assess and refactor your code. This usually happens > early enough that it only takes a few minutes. Short circuiting essentially > gives you the ability to not feel the pain. Its like CIPA [0], but for code. > I would fear that the code would get so bad that by the time the test cried > with pain your code was already beyond easy repair and instead required > invasive surgery. > >>> > >>> Tests are part of the nervous system of your application. When they > hurt, they''re telling you something isn''t right and that it should be > addressed, > >>> > >>> > >>> > >>> I wouldn''t really say that anything I have been presenting has been a > result of ''pains'', > >>> more so an observation on how an example group with other example > groups can be much more readable > >>> for myself and for other developers when they need to read the specs. > Stubbing everything at the top doesn''t > >>> make complete sense. Why not stub inside the example group that has a > NICE describe statement telling you > >>> what this stubbing is related to. We can''t do this because the first > examples will blow up due to having to execute > >>> all the code. > >>> > >>> Take the 2 examples: > >>> > >>> > ------------------------------------------------------------------------------------------------------------------------ > >>> PeopleController > >>> # stub everything way up here at the top where these > >>> # definitions are out of context (by means of position) with following > examples > >>> # > >>> # stub controller requirments > >>> # stub logged in requirement > >>> # stub account requirement > >>> # stub no account requirement > >>> # stub account owns person > >>> # stub account doesn''t own person > >>> > >>> > >>> PeopleController with before filters > >>> - should require user > >>> > >>> PeopleController with a logged in user > >>> - should find user > >>> > >>> PeopleController with a logged in user who has an account > >>> - should find account > >>> > >>> PeopleController with a logged in user who doesnt have an account > >>> - shouldn''t find account > >>> - should redirect ... > >>> > >>> PeopleController with a logged in user who has an account the person > belongs to > >>> - should find person > >>> - should assign person for the view > >>> > >>> PeopleController with a logged in user who has an account the requested > person does not belong to > >>> - should not find person > >>> - should ... > >>> > >>> > ------------------------------------------------------------------------------------------------------------------------ > >>> PeopleController > >>> # stub the minimum needed to get to the first example group up and > running > >>> > >>> PeopleController with before filters > >>> - should require user > >>> > >>> PeopleController with a logged in user > >>> # stub logged in requirement > >>> - should find user > >>> > >>> PeopleController with a logged in user who has an account > >>> # stub account requirement > >>> - should find account > >>> > >>> PeopleController with a logged in user who doesnt have an account > >>> # stub no account requirement > >>> - shouldn''t find account > >>> - should redirect ... > >>> > >>> PeopleController with a logged in user who has an account the person > belongs to > >>> # stub account owns person > >>> - should find person > >>> - should assign person for the view > >>> > >>> PeopleController with a logged in user who has an account the requested > person does not belong to > >>> # stub account doesn''t own person > >>> - should not find person > >>> - should ... > >>> > >>> > ------------------------------------------------------------------------------------------------------------------------ > >>> > >>> I prefer the second group, but unfortunately I am not able to write my > specs in this organized fashion. > >>> Just sayin. > >> > >> I appreciate the communication value you''re looking for, and you can > >> get it by stubbing everything you need to keep execution going > >> before(:each) example and then set message expectations > >> (should_receive) inside each example that help tell the story of that > >> example. > >> > >> PeopleController > >> # stub everything way up here at the top where these > >> # definitions are out of context (by means of position) with following > examples > >> # > >> # stub controller requirments > >> # stub logged in requirement > >> # stub account requirement > >> # stub no account requirement > >> # stub account owns person > >> # stub account doesn''t own person > >> > >> PeopleController with before filters > >> - should require user > >> > >> PeopleController with a logged in user > >> # expect logged in query > >> - should find user > >> > >> PeopleController with a logged in user who has an account > >> # expect logged in query > >> # expect account query > >> - should find account > >> > >> etc > >> > >> HTH, > >> David > > > > Yep, thats exactly what I''ve been practicing, and while its not exactly > what I want, it does work nicely. > > Thank you David > > > I''m gonna make another REALLY strong case for allowing the ability to stop > example execution and test code incrementally. I currently have over 1700 > examples for the current application I''m working on, and one little line of > code that I added in my App controller ( before_filter :set_location ) > brought on almost 1100 errors across my tests. Now I know people will say > that the requirements weren''t understood at the beginning of the application > and that it could have been avoided with better planning... but this isn''t > the case. > > I now have to go into each of my controller tests and add the stub into > every before declaration to clear up my errors. Not fun, and could''ve been > avoided completely. > > Britt > > _________________________________________________________________ > Enter the Zune-A-Day Giveaway for your chance to win ? day after day after > day > > http://www.windowslive-hotmail.com/ZuneADay/?locale=en-US&ocid=TXT_TAGLM_Mobile_Zune_V1 > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-- Zach Dennis http://www.continuousthinking.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20080703/35195ea2/attachment.html>
On Sun, Jun 29, 2008 at 9:18 AM, Britt Mileshosky <mileshosky at hotmail.com> wrote:> > However, do you see where something like a return statement or end example statement could be beneficial? > If you are working from the top down with your controller action execution, then you only need to test your expectation > and then bail out of your action. No need to further test or meet requirements on anything else in that action because your > single test has been met. > > - in my example for making sure I find a user, I''d like to end execution once I DID find the user, i shouldn''t have to satisfy > requirements about finding an account and a person... I''ll write those expectations later in another nested describe group, as you > can see here, in a top down process > > PeopleController with a logged in user > - should find user > > PeopleController with a logged in user who has an account > - should find account > > PeopleController with a logged in user who doesnt have an account > - shouldn''t find account > - should redirect ... > > PeopleController with a logged in user who has an account the person belongs to > - should find person > - should assign person for the view > > PeopleController with a logged in user who has an account the requested person does not belong to > - should not find person > - should ...Hi Britt, Quick little thought experiment for you: Imagine you write the examples as you have described, stubbing only the minimum amount of things necessary and then ending the example once you''ve reached a certain point. So for the action def some_action @user = self.current_user @account = self.current_account if self.has_account? @person = @account.people.find(params[:person]) end your first example only runs until current_user, your second example runs only until has_account, and your third one runs only until account.people.find. So far so good. What happens when you change the implementation to: def some_action @user = self.current_user if self.has_account? @account = self.current_account @person = @account.people.find(params[:person]) end end which I could totally see doing, given that the original implementation will raise an error on the @account.people call on those occasions where has_account? returns false, making @account nil. Can you spot the problem? Your specs will now fail because you had only stubbed enough to get to a particular line. The specs are very tightly coupled to the implementation, which sucks. Also, if you were to do this incremental stubbing, you would have a hard time moving examples around, because the nested examples would rely on context set up by the parents. This technique, after looking a bit more deeply at it, would lead to specs that are tightly coupled to the implementation and to each other. Tight coupling is usually bad, and tight coupling from both angles is a recipe for total frustration. I hope that is helpful. Pat