Question

I am writing my first controller tests for Rails in Rspec. In testing the create action, I want to write a test that verifies that the 'new' template is rendered when the form is submitted with invalid attributes. In this case, that means a field is left blank.

I have found several examples that I have tried to follow verbatim. However, when using Rspec to trigger the create action, it seems like ActiveRecord actually tries to create that record which, due to validations, fails. Thus, my test fails before I even get to test the redirect function. This does not seem to be an issue for the people writing the tutorials or StackOverflow answers.

What is the best way to test the create action in a controller, given invalid attributes?

Rails 4.0.0, Ruby 2.0.0, Rspec 3.0.0.beta2

order_items_controller_spec

describe "POST create" do
    context "with invalid attributes" do
        it "re-renders the new method" do
            post :create, order_item: FactoryGirl.attributes_for(:order_item, :buyer_id => nil)
            expect( response ).to render_template :new
        end
    end
end

order_items_controller

def create
    @order_item = OrderItem.new(order_item_params)
    respond_to do |format|
        if @order_item.save!
            format.html { redirect_to cart_path(@order_item), notice: 'Your trip has been added to your cart.' }
            format.json { render action: 'show', status: :created, location: @order_item }
        else
            format.html { redirect_to new_order_item_path, notice: 'We were unable to customize your trip.' }
            format.json { render json: @order_item.errors, status: :unprocessable_entity }
        end
    end
end

rspec error message:

 OrderItemsController POST create with invalid attributes re-renders the new method
     Failure/Error: post :create, order_item: FactoryGirl.attributes_for(:order_item, :buyer_id => nil)
     ActiveRecord::RecordInvalid:
     Validation failed: Buyer can't be blank
    # ./app/controllers/order_items_controller.rb:30:in `block in create'
    # ./app/controllers/order_items_controller.rb:29:in `create'
    # ./spec/controllers/order_items_controller_spec.rb:43:in `block (4 levels) in <top (required)>'

Thanks in advance.

Était-ce utile?

La solution

Your test looks good; it's actually your code which is failing to work as you expect when the save fails. When you say "ActiveRecord actually tries to create that record which, due to validations, fails", that's exactly what you want your test to be doing, because you are trying to test what happens if the validation fails.

In your controller you are saving the record with save!. This will cause an error be raised if the save fails, which is why you immediately see a failure in rspec rather than it going on to the new view.

Instead you want to use save (without the bang). This will return true/false depending on the save success so you can use it in a condition.

Your controller code should be:

def create
    @order_item = OrderItem.new(order_item_params)
    respond_to do |format|
        if @order_item.save    ### ! removed
          ...

Autres conseils

Don't use 'save!' ... you should be using 'save' which will return false if not valid.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top