On 6/11/07, Shane Mingins <smingins at elctech.com>
wrote:> Hi All
>
> So I am a first-time caller ;-) ... and have been trying to apply
> RSpec to the depot example in Dave Thomas'' book as I build the
> application.
>
> I am having a problem testing the admin controller create method and
> cannot quite see where I am going wrong so was hoping for a pointer :-)
>
> My spec looks like:
>
> describe AdminController do
>
> before(:each) do
> @product = mock("product")
> # Generally, prefer stub! over should_receive in setup.
> @product.stub!(:new_record?).and_return(false)
> Product.stub!(:new).and_return(@product)
> end
>
> it "should create a new, unsaved product on GET to new" do
> # Using should_receive here overrides the stub in setup. Even
> # though it is the same as the stub, using should_receive sets
> # an expectation that will be verified. It also helps to
> # better express the intent of this example.
> Product.should_receive(:new).and_return(@product)
> get :new
> end
>
> it "should assign new product to template on GET to new" do
> get :new
> assigns[:product].should equal(@product)
> end
>
> it "should render ''product/new'' on GET to
new" do
> get :new
> response.should render_template(:new)
> end
>
> it "should tell the Product model to save a new product on POST to
> create" do
> attributes = {"title" => ''Apple Wireless
Keyboard'',
> "description" => ''Really cool
wireless keyboard'',
> "image_url" => ''a.gif'',
> "price" => 1.00}
>
> Product.should_receive(:new).with(attributes)
> Product.should_receive(:save).with(:no_arg)
>
> post :create, :product => attributes
> end
>
> end
>
>
> Which I copied and modified from the example.
>
> The code in the controller looks like:
>
> 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
Two problems.
1. The return value from Product.new(params[:product]) gets assigned
to @product. You need to tell the :new method to return something when
setting up the Message Expectation.
2. :save is getting called on @product, not the Product class.
To solve both of these, create a mock instance of product and tell
Product to return that for :new So replace this:
Product.should_receive(:new).with(attributes)
Product.should_receive(:save).with(:no_arg)
with this:
product = mock("product")
product.should_receive(:save).with(no_args).and_return(true)
Product.should_receive(:new).with(attributes).and_return(product)
Note that I used no_args instead of :no_args. The Symbol is deprecated
and replaced by a method.
Also, since you''re telling product to return true for :save,
you''re
describing only one branch of create. To describe the other branch you
can have a separate example in which it returns false and then say:
response.should render_template(''new'')
Enjoy,
David
>
>
> I am guessing that I haven''t quite got the mock/stub setup
correctly??
>
> The error I get is:
>
> 1)
> NoMethodError in ''AdminController should tell the Product model to
> save a new product on POST to create''
> You have a nil object when you didn''t expect it!
> You might have expected an instance of ActiveRecord::Base.
> The error occurred while evaluating nil.save
> /Users/smingins/Work/depot/config/../app/controllers/
> admin_controller.rb:25:in `create''
> ./spec/controllers/admin_controller_spec.rb:41:
>
> Finished in 0.226535 seconds
>
>
> I have been playing around with things but without any luck. The nil
> error does strike me as rather odd but the test reads as I would have
> thought it should ... but obviously I am missing something.
>
> Cheer
> Shane
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>