Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rspec controller testing, Expected response to be a <redirect>, but was <200>

I'm using rspec and Factory Girl for testing. When testing the POST #create section of my posts_controller I'm getting the error in the title.

Failures:

  1) PostsController POST #create with valid attributes redirects to the post
     Failure/Error: response.should redirect_to Post.last
       Expected response to be a <redirect>, but was <200>
     # ./spec/controllers/posts_controller_spec.rb:59:in `block (4 levels) in <top (required)>'

This is the code from the spec being tested. I'm sure it's not the most efficient way of doing this, but it does work.

  def create

    @post = Post.new(
      :text => post_params[:text],
      :embed => post_params[:embed],
      :user => current_user,
      :title => post_params[:title],
      :tag_list => post_params[:tag_list],
      :cagegory_ids => post_params[:category_ids]
    )


    if @post.save
      redirect_to @post
    else
      render 'new'
    end

  end

...

  private    
    def post_params
      params.require(:post).permit(:title, :text, :embed, :user_id, :tag_list,
                               :category_ids => [])
    end

Here's the factory.

FactoryGirl.define do  
  factory :post do
    title { Faker::Lorem.characters(char_count = 20) }
    text { Faker::Lorem.characters(char_count = 150) }
    user
    categories {
      Array(5..10).sample.times.map do
        FactoryGirl.create(:category)
      end
    }
  end
end

And the relevant part of the spec

  describe "POST #create" do
    context "with valid attributes" do
      it "saves the new post" do
        expect{
                post :create, post: FactoryGirl.create(:post).attributes
              }.to change(Post,:count).by(1)

      end

      it "redirects to the post" do
        post :create, post: FactoryGirl.create(:post).attributes
        response.should redirect_to Post.last
      end        
    end
  end

The other test, "saves the new post," works fine. I've tried other variations of the redirect_to line, such as "redirect_to(posts_path(assigns[:post])) and it throws the same error.

Any ideas?

like image 547
travisnewman Avatar asked Feb 15 '14 19:02

travisnewman


2 Answers

OK, I fixed my problem. It isn't pretty but it works.

The issue is with Factory Girl and associations, and I'm definitely not the first to have that problem, but none of the other solutions worked.

I ended up adding this before :each at the top of the POST #create section...

  describe "POST #create" do
    before :each do
      Post.destroy_all
      @cat = FactoryGirl.create(:category)
      @newpost = FactoryGirl.build(:post)
      @post_params = {category_ids: [@cat.id]}.merge(@newpost.attributes)
    end
...

...to put the post params into a new hash that I could call later on in the code like this...

  it "saves the new post" do
    expect{
             post :create, post: @post_params
           }.to change(Post,:count).by(1)
  end

  it "redirects to the post" do
    post :create, post: @post_params
    response.should redirect_to Post.last
  end 

So this is solved. It adds a bit of overhead to the test but it works. I won't mark this as THE solution for a couple of days in case someone else comes around with some better, simpler code. I definitely welcome any more ideas.

like image 159
travisnewman Avatar answered Sep 28 '22 10:09

travisnewman


I assume the problem is in factory. Most likely post instance didn't pass validations and controller renders new view, which is not redirect, but success 200. Add logger in the controller and take a look if record actually saves. You can also read through test log tail -f log/test.log.

like image 33
Mikhail Nikalyukin Avatar answered Sep 28 '22 08:09

Mikhail Nikalyukin