Given this code (which renders rjs), I''m faced with the fixture- driven way of spec-ing or mocking. How the heck to you mock this so the code at line (2) and (4) work right? I''m still struggling with mocks but it seems like this can be done. Forgive the naivety of this question. 1. def change_quantity 2. @line_item = LineItem.find_by_id(params[:id]) 3. unless @line_item.nil? 4. @line_item.update_attribute(:quantity, params[:quantity]) 5. @extension_id = "extension#{params[:id]}" 6. end 7. end Thanks
try this: @line_item = mock("line_item") LineItem.should_receive(:find_by_id).with(3).and_return(@line_item) @line_item.should_receive(:update_attribute).with(:quantity, 1) get :change_quantity, :id => 3, :quantity => 1 On 1/5/07, s.ross <cwdinfo at gmail.com> wrote:> Given this code (which renders rjs), I''m faced with the fixture- > driven way of spec-ing or mocking. How the heck to you mock this so > the code at line (2) and (4) work right? I''m still struggling with > mocks but it seems like this can be done. Forgive the naivety of this > question. > > 1. def change_quantity > 2. @line_item = LineItem.find_by_id(params[:id]) > 3. unless @line_item.nil? > 4. @line_item.update_attribute(:quantity, params[:quantity]) > 5. @extension_id = "extension#{params[:id]}" > 6. end > 7. end > > Thanks > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
What I came up with was: context "The cart controller" do controller_name "carts" integrate_views setup do @cart = mock("cart") @cart.stub!(:new_record).and_return(false) @cart.stub!(:new).and_return(@cart) @cart.stub!(:total_price).and_return(35.00) @cart.stub!(:total_quantity).and_return(1) @cart.stub!(:empty?).and_return(false) @line_item = mock("line_item") LineItem.stub!(:find_by_id).and_return(@line_item) @line_item.should_receive(:update_attribute).with(:quantity, "1").and_return(true) @line_item.stub!(:extension).and_return(25.00) end specify "should allow change of quantity" do post :change_quantity, {:id => 1, :quantity => 1} response.should_be_success assigns[:extension_id].should == "extension1" assigns[:line_item].should_be(@line_item) controller.should_render_rjs :replace_html, ''cartstatus'', "(1 item, $35.00)" end end but somehow it seems a bit brittle. This is really what should happen if a user changes quantity, but the mocks seem like they won''t flex or bend easily for further reuse. Any thoughts on this? On Jan 5, 2007, at 2:14 PM, Courtenay wrote:> try this: > > > @line_item = mock("line_item") > LineItem.should_receive(:find_by_id).with(3).and_return(@line_item) > @line_item.should_receive(:update_attribute).with(:quantity, 1) > > get :change_quantity, :id => 3, :quantity => 1 > > > On 1/5/07, s.ross <cwdinfo at gmail.com> wrote: >> Given this code (which renders rjs), I''m faced with the fixture- >> driven way of spec-ing or mocking. How the heck to you mock this so >> the code at line (2) and (4) work right? I''m still struggling with >> mocks but it seems like this can be done. Forgive the naivety of this >> question. >> >> 1. def change_quantity >> 2. @line_item = LineItem.find_by_id(params[:id]) >> 3. unless @line_item.nil? >> 4. @line_item.update_attribute(:quantity, params[:quantity]) >> 5. @extension_id = "extension#{params[:id]}" >> 6. end >> 7. end >> >> Thanks >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users >> > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
On 1/6/07, s.ross <cwdinfo at gmail.com> wrote:> What I came up with was: > > context "The cart controller" do > controller_name "carts" > integrate_views > > setup do > @cart = mock("cart") > @cart.stub!(:new_record).and_return(false) > @cart.stub!(:new).and_return(@cart) > @cart.stub!(:total_price).and_return(35.00) > @cart.stub!(:total_quantity).and_return(1) > @cart.stub!(:empty?).and_return(false) > > @line_item = mock("line_item") > LineItem.stub!(:find_by_id).and_return(@line_item) > @line_item.should_receive(:update_attribute).with(:quantity, > "1").and_return(true)I try to avoid using should_receive in setup, so I''d do this here: @line_item.stub!(:update_attribute).and_return(true) and then override the method stub w/ a mock expectation in the specify block. The idea is that you put all of the stuff in setup that must be there for the code to execute, and put the details in the specs that are interesting for that spec.> @line_item.stub!(:extension).and_return(25.00) > end > > specify "should allow change of quantity" do > post :change_quantity, {:id => 1, :quantity => 1} > response.should_be_success > assigns[:extension_id].should == "extension1" > assigns[:line_item].should_be(@line_item) > controller.should_render_rjs :replace_html, ''cartstatus'', > "(1 item, $35.00)" > end > end > > but somehow it seems a bit brittle. This is really what should happen > if a user changes quantity, but the mocks seem like they won''t flex > or bend easily for further reuse. Any thoughts on this?Within this context they absolutely will flex or bend by overriding the method stubs (functioning as defaults) w/ mock expectations. Also, I might approach this differently. The behaviour here that you want to spec is that when changing quantity some things should happen. So.... context "Given a request to change quantity, the CartController should" do controller_name "carts" integrate_views setup do @cart = mock("cart") @cart.stub!(:new_record).and_return(false) @cart.stub!(:total_price).and_return(35.00) @cart.stub!(:total_quantity).and_return(1) @cart.stub!(:empty?).and_return(false) Cart.stub!(:new).and_return(@cart) @line_item = mock("line_item") @line_item.stub!(:update_attribute).and_return(true) @line_item.stub!(:extension).and_return(25.00) LineItem.stub!(:find_by_id).and_return(@line_item) post :change_quantity, {:id => 1, :quantity => 1} end specify "respond w/ success" do response.should_be_success end specify "assign exension_id" do assigns[:extension_id].should == "extension1" end specify "assign line_item" do assigns[:line_item].should_be(@line_item) end specify "update the html (using rjs)" do controller.should_render_rjs :replace_html, ''cartstatus'', "(1 item, $35.00)" end end This would then read: Given a request to change quantity, the CartController should - respond w/ success - assign exension_id - assign line_item - update the html (using rjs) If you''re concerned about reuse of the stubs, you can do this: module Stubs def new_stub_cart cart = mock("cart") cart.stub!(:new_record).and_return(false) cart.stub!(:total_price).and_return(0.0) cart.stub!(:total_quantity).and_return(0) cart.stub!(:empty?).and_return(false) cart end def new_stub_line_item line_item = mock("line_item") line_item.stub!(:update_attribute).and_return(true) line_item.stub!(:extension).and_return(0) line_item end def stub_cart @stub_cart ||= new_stub_cart end def stub_line_item @stub_line_item ||= new_stub_line_item end end context "Given a request to change quantity, the CartController should" do include Stubs controller_name "carts" integrate_views setup do Cart.stub!(:new).and_return(stub_cart) LineItem.stub!(:find_by_id).and_return(stub_line_item) end ... end Now any new spec that requires specific values can use stub_cart.should_receive(:total_price).and_return(25.00), for example.> > On Jan 5, 2007, at 2:14 PM, Courtenay wrote: > > > try this: > > > > > > @line_item = mock("line_item") > > LineItem.should_receive(:find_by_id).with(3).and_return(@line_item) > > @line_item.should_receive(:update_attribute).with(:quantity, 1) > > > > get :change_quantity, :id => 3, :quantity => 1 > > > > > > On 1/5/07, s.ross <cwdinfo at gmail.com> wrote: > >> Given this code (which renders rjs), I''m faced with the fixture- > >> driven way of spec-ing or mocking. How the heck to you mock this so > >> the code at line (2) and (4) work right? I''m still struggling with > >> mocks but it seems like this can be done. Forgive the naivety of this > >> question. > >> > >> 1. def change_quantity > >> 2. @line_item = LineItem.find_by_id(params[:id]) > >> 3. unless @line_item.nil? > >> 4. @line_item.update_attribute(:quantity, params[:quantity]) > >> 5. @extension_id = "extension#{params[:id]}" > >> 6. end > >> 7. end > >> > >> Thanks > >> _______________________________________________ > >> rspec-users mailing list > >> rspec-users at rubyforge.org > >> http://rubyforge.org/mailman/listinfo/rspec-users > >> > > _______________________________________________ > > rspec-users mailing list > > rspec-users at rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Wow! Thanks. I''ll look at this to see how it works for me. Steve On Jan 6, 2007, at 5:20 AM, David Chelimsky wrote:> On 1/6/07, s.ross <cwdinfo at gmail.com> wrote: >> What I came up with was: >> >> context "The cart controller" do >> controller_name "carts" >> integrate_views >> >> setup do >> @cart = mock("cart") >> @cart.stub!(:new_record).and_return(false) >> @cart.stub!(:new).and_return(@cart) >> @cart.stub!(:total_price).and_return(35.00) >> @cart.stub!(:total_quantity).and_return(1) >> @cart.stub!(:empty?).and_return(false) >> >> @line_item = mock("line_item") >> LineItem.stub!(:find_by_id).and_return(@line_item) >> @line_item.should_receive(:update_attribute).with(:quantity, >> "1").and_return(true) > > I try to avoid using should_receive in setup, so I''d do this here: > > @line_item.stub!(:update_attribute).and_return(true) > > and then override the method stub w/ a mock expectation in the specify > block. The idea is that you put all of the stuff in setup that must be > there for the code to execute, and put the details in the specs that > are interesting for that spec. > >> @line_item.stub!(:extension).and_return(25.00) >> end >> >> specify "should allow change of quantity" do >> post :change_quantity, {:id => 1, :quantity => 1} >> response.should_be_success >> assigns[:extension_id].should == "extension1" >> assigns[:line_item].should_be(@line_item) >> controller.should_render_rjs :replace_html, ''cartstatus'', >> "(1 item, $35.00)" >> end >> end >> >> but somehow it seems a bit brittle. This is really what should happen >> if a user changes quantity, but the mocks seem like they won''t flex >> or bend easily for further reuse. Any thoughts on this? > > Within this context they absolutely will flex or bend by overriding > the method stubs (functioning as defaults) w/ mock expectations. > > Also, I might approach this differently. The behaviour here that you > want to spec is that when changing quantity some things should happen. > So.... > > context "Given a request to change quantity, the CartController > should" do > controller_name "carts" > integrate_views > > setup do > @cart = mock("cart") > @cart.stub!(:new_record).and_return(false) > @cart.stub!(:total_price).and_return(35.00) > @cart.stub!(:total_quantity).and_return(1) > @cart.stub!(:empty?).and_return(false) > Cart.stub!(:new).and_return(@cart) > > @line_item = mock("line_item") > @line_item.stub!(:update_attribute).and_return(true) > @line_item.stub!(:extension).and_return(25.00) > LineItem.stub!(:find_by_id).and_return(@line_item) > > post :change_quantity, {:id => 1, :quantity => 1} > end > > specify "respond w/ success" do > response.should_be_success > end > > specify "assign exension_id" do > assigns[:extension_id].should == "extension1" > end > > specify "assign line_item" do > assigns[:line_item].should_be(@line_item) > end > > specify "update the html (using rjs)" do > controller.should_render_rjs :replace_html, > ''cartstatus'', > "(1 item, $35.00)" > end > end > > This would then read: > > Given a request to change quantity, the CartController should > - respond w/ success > - assign exension_id > - assign line_item > - update the html (using rjs) > > If you''re concerned about reuse of the stubs, you can do this: > > module Stubs > def new_stub_cart > cart = mock("cart") > cart.stub!(:new_record).and_return(false) > cart.stub!(:total_price).and_return(0.0) > cart.stub!(:total_quantity).and_return(0) > cart.stub!(:empty?).and_return(false) > cart > end > > def new_stub_line_item > line_item = mock("line_item") > line_item.stub!(:update_attribute).and_return(true) > line_item.stub!(:extension).and_return(0) > line_item > end > > def stub_cart > @stub_cart ||= new_stub_cart > end > > def stub_line_item > @stub_line_item ||= new_stub_line_item > end > end > > context "Given a request to change quantity, the CartController > should" do > include Stubs > controller_name "carts" > integrate_views > > setup do > Cart.stub!(:new).and_return(stub_cart) > LineItem.stub!(:find_by_id).and_return(stub_line_item) > end > ... > end > > Now any new spec that requires specific values can use > stub_cart.should_receive(:total_price).and_return(25.00), for example. > > >> >> On Jan 5, 2007, at 2:14 PM, Courtenay wrote: >> >>> try this: >>> >>> >>> @line_item = mock("line_item") >>> LineItem.should_receive(:find_by_id).with(3).and_return(@line_item) >>> @line_item.should_receive(:update_attribute).with(:quantity, 1) >>> >>> get :change_quantity, :id => 3, :quantity => 1 >>> >>> >>> On 1/5/07, s.ross <cwdinfo at gmail.com> wrote: >>>> Given this code (which renders rjs), I''m faced with the fixture- >>>> driven way of spec-ing or mocking. How the heck to you mock this so >>>> the code at line (2) and (4) work right? I''m still struggling with >>>> mocks but it seems like this can be done. Forgive the naivety of >>>> this >>>> question. >>>> >>>> 1. def change_quantity >>>> 2. @line_item = LineItem.find_by_id(params[:id]) >>>> 3. unless @line_item.nil? >>>> 4. @line_item.update_attribute(:quantity, params[:quantity]) >>>> 5. @extension_id = "extension#{params[:id]}" >>>> 6. end >>>> 7. end >>>> >>>> Thanks >>>> _______________________________________________ >>>> rspec-users mailing list >>>> rspec-users at rubyforge.org >>>> http://rubyforge.org/mailman/listinfo/rspec-users >>>> >>> _______________________________________________ >>> rspec-users mailing list >>> rspec-users at rubyforge.org >>> http://rubyforge.org/mailman/listinfo/rspec-users >> >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users >> > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users