How to get rspec coverage for the failure of .save

Viewed 413

In my controller I have the following code:

def create
    @post = Post.new(post_params)
    if @post.save
      flash[:notice] = "#{@post.title} was successfully created."
      redirect_to post_path
    else
      flash[:alert] = @post.errors.full_messages
      render :new
    end
end

I've managed to write rspec code to cover the true statement within a feature spec, however I am struggling for the false statement. So far this is the rspec I have come up with to solve my problem (placed in posts_controller_spec.rb):

it 'should return false and render the new template' do 

    allow_any_instance_of(Post).to receive(:valid?).and_return(false)

    expect(response).to render_template(:new)

end

Unfortunately, I am met with the following error:

Failures:

  1) PostsController create should return 
     Failure/Error: expect(response).to render_template(:new)
       expecting <"new"> but rendering with <[]>

I've tried looking at other questions on stackoverflow as well as other suggestions online, but can't seem to figure it out.

Any help would be much appreciated :)

1 Answers

In your test, you never call the controller.

it 'renders the new template' do 
  allow_any_instance_of(Post).to receive(:valid?).and_return(false)

  post :create, params: {...}

  expect(response).to render_template(:new)
end

It would be more direct to do receive(:save).and_return(false).


However, there's no need for a mock here. Send invalid Post parameters.

context 'when the Post params are invalid' do
  let(:params) do
    {
      post: { something: "invalid" }
    }
  end

  it 'does not make a Post, renders the new template, and flashes an error' do
    expect {
      post :create, params: params
    }.to change {
      Post.count
    }.by(0)

    expect(response).to render_template(:new)
    expect(flash[:alert]).not_to be_empty
  end
end
Related