Hi, I''m a rspec newbie. I''m having trouble with rspec''ing a simple controller to Create a record. I''ve tried a couple of approaches and still get errors: Mock ''remedy'' expected :save! with (any args) once, but received it 0 times -or- Mock ''Remedy'' received unexpected message :save with (no args). Here are my two sample approaches: describe "Create with a valid product and authenticated user" do controller_name :products before(:each) do @product= mock(Product) Product.stub!(:new).and_return(@product) end it "should tell the Product model to create a new product" do #mock_user_authentication(true) Product.should_receive(:new).with(:params).and_return(@product) post ''create'', :product => :params end end describe "Create with a valid product and authenticated user with everything in setup" do controller_name :product setup do @product= mock(:product, :null_object => true) Product.stub!(:new).and_return(@product) @product.should_receive(:save!).and_return(true) #mock_user_authentication(true) post :create, :product => {''name'' => ''a new product'', ''description'' => ''an editable description'', ''user_id'' => 1, ''klass'' => 1} end specify "should redirect to list" do response.should redirect_to(:action => ''list'') end Any ideas what I am doing wrong? Thanks, Steve
Looks like you''ve configured your mock to receive a call to #save! while your controller is actually calling #save. #save! is not the same as #save! On 5/8/07, Steve Odom <steve.odom at gmail.com> wrote:> Hi, > > I''m a rspec newbie. I''m having trouble with rspec''ing a simple > controller to Create a record. > > I''ve tried a couple of approaches and still get errors: > Mock ''remedy'' expected :save! with (any args) once, but received it 0 > times > > -or- > > Mock ''Remedy'' received unexpected message :save with (no args). > > Here are my two sample approaches: > > describe "Create with a valid product and authenticated user" do > controller_name :products > > before(:each) do > @product= mock(Product) > Product.stub!(:new).and_return(@product) > end > > it "should tell the Product model to create a new product" do > #mock_user_authentication(true) > Product.should_receive(:new).with(:params).and_return(@product) > post ''create'', :product => :params > end > end > > describe "Create with a valid product and authenticated user with > everything in setup" do > controller_name :product > > setup do > @product= mock(:product, :null_object => true) > Product.stub!(:new).and_return(@product) > @product.should_receive(:save!).and_return(true) > #mock_user_authentication(true) > > post :create, :product => {''name'' => ''a new product'', > ''description'' => ''an editable description'', > ''user_id'' => 1, ''klass'' => 1} > end > > specify "should redirect to list" do > response.should redirect_to(:action => ''list'') > end > > Any ideas what I am doing wrong? > > Thanks, > > Steve > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Steve, First concern is that your mock objects got stubbed after it is returned by new method stub. I alway tend to prepair mock/stub completely before I use it as argument or any other way. Second is that tyou try to check that your controller''s setup creates a valid product, but you use mocks, it''s up to you to decide whether your model is valid or not, what it expects to receive and what it returns. It looks like you get this idea from your models specs where such a check is useful. Anyway I feel your problem is that you stub :save! but use :save that is unexpected. Could you post your controller code please (create action)? On 08/05/07, Steve Odom <steve.odom at gmail.com> wrote:> Hi, > > I''m a rspec newbie. I''m having trouble with rspec''ing a simple > controller to Create a record. > > I''ve tried a couple of approaches and still get errors: > Mock ''remedy'' expected :save! with (any args) once, but received it 0 > times > > -or- > > Mock ''Remedy'' received unexpected message :save with (no args). > > Here are my two sample approaches: > > describe "Create with a valid product and authenticated user" do > controller_name :products > > before(:each) do > @product= mock(Product) > Product.stub!(:new).and_return(@product) > end > > it "should tell the Product model to create a new product" do > #mock_user_authentication(true) > Product.should_receive(:new).with(:params).and_return(@product) > post ''create'', :product => :params > end > end > > describe "Create with a valid product and authenticated user with > everything in setup" do > controller_name :product > > setup do > @product= mock(:product, :null_object => true) > Product.stub!(:new).and_return(@product) > @product.should_receive(:save!).and_return(true) > #mock_user_authentication(true) > > post :create, :product => {''name'' => ''a new product'', > ''description'' => ''an editable description'', > ''user_id'' => 1, ''klass'' => 1} > end > > specify "should redirect to list" do > response.should redirect_to(:action => ''list'') > end > > Any ideas what I am doing wrong? > > Thanks, > > Steve > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-- This was freedom. Losing all hope was freedom. Chasing the beauty in programming: www.ruby-lang.org | www.rubyonrails.org
Thanks Aslak and Michael. You were both right. Changing save! to save in my second context made that test pass. Michael also mentioned... >First concern is that your mock objects got stubbed after it is >returned by new method stub. I alway tend to prepair mock/stub >completely before I use it as argument or any other way. I''m not sure what you mean by prepair mock/stub completely. Can you provide a sample of how you would rspec a simple create action, such as: def create @product = Product.new(params[:product]) if @product.save flash[:notice] = ''Product was successfully created.'' redirect_to :action => ''list'' else render :action => ''new'' end end >Second is that tyou try to check that your controller''s setup creates >a valid product, but you use mocks, it''s up to you to decide whether >your model is valid or not, what it expects to receive and what it >returns. It looks like you get this idea from your models specs where >such a check is useful. I might be misunderstanding you, but I thought it was preferable to mock/stub all the ActiveRecord instances in your controller and only focus on the controller responsibilities. thanks for the help. Steve On May 8, 2007, at 10:43 AM, Michael Klishin wrote:> t-------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20070508/4cb7eba5/attachment.html
On 08/05/07, Steve Odom <steve.odom at gmail.com> wrote:> I''m not sure what you mean by prepair mock/stub completely. Can you provide > a sample of how you would rspec a simple create action, such as: > > def create > @product = Product.new(params[:product]) > if @product.save > flash[:notice] = ''Product was successfully created.'' > redirect_to :action => ''list'' > else > render :action => ''new'' > end > endI am still using 0.8.2 so: specify "should save valid object and redirect to list of objects" do @model = mock("model") @model.should_receive(:save).and_return(true) post :create, { :product => @model } assigns[:product].should be_instance_of(Product) # not nil and instance of right class # save call verified by mock object response.should be_redirect # redirect controller.should_redirect_to(:action => :list) # redirected to :list end specify "should redirect to new object page if instance cannot be saved" do @model = mock("model") @model.should_receive(:save).and_return(false) post :create, { :product => @model } assigns[:product].should be_instance_of(Product) # not nil and instance of right class # save call verified by mock object response.should be_redirect # redirect controller.should_redirect_to(:action => :new) # redirected to :new end> I might be misunderstanding you, but I thought it was preferable to > mock/stub all the ActiveRecord instances in your controller and only focus > on the controller responsibilities.Exactly. But no need to verify that your mock creates valid object :) If I got the idea of last example right... It was what you trying to do. -- This was freedom. Losing all hope was freedom. Chasing the beauty in programming: www.ruby-lang.org | www.rubyonrails.org