If I stub out .save method in my controller test how can I check the correct show template is rendered?

2k views Asked by At

I am trying to test a controller create method in a rails app using RSpec as shown below:

def create
  @user = User.new(user_params)
  if @user.save
     redirect_to user_path(@user.id)
  else
     render new_user_path
     flash[:error] = "User not saved"
  end
end

However if i stub out .new to prevent the test from using Active Record and the User model by forcing it to return true the id of the @user is not set by .save as normal so I cannot test for it redirecting to user_path(@user.id) as @user.id is nil

Here is my initial test for RSpec:

it "creates a user and redirects" do
  expect_any_instance_of(User).to receive(:save).and_return(true) 
  post :create, { user: {name: "John", username: "Johnny98", email: "[email protected]"} }

  expect(assigns(:user).name).to eq("John")
  expect(response).to redirect_to user_path(assigns(:user))
end

How should I test for this redirect in RSpec.

2

There are 2 answers

4
maxim.tsaplin On BEST ANSWER

You should use mocks - https://www.relishapp.com/rspec/rspec-mocks/docs.

user = double("user", id: 1, save: true)

Then you should mock you method with double you've just created

expect(User).to receive(:new).and_return(user)

And then test redirect.

expect(response).to redirect_to user_path(user)

I hope this will help.

2
Rustam Gasanov On

I would do it in this way:

  it 'should redirect to a user if save returned true' do
    @user_instance = double
    @user_id = double

    allow(User).to receive(:new).and_return(@user_instance)
    allow(@user_instance).to receive(:save).and_return(true)
    allow(@user_instance).to receive(:id).and_return(@user_id)

    post :create, {:user => valid_attributes}

    expect(response).to redirect_to(user_path(@user_id))
  end