[rspec-users] Testing create in Rails controller

David Chelimsky dchelimsky at gmail.com
Mon Jun 11 07:25:17 EDT 2007


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
>


More information about the rspec-users mailing list