I am trying to write some RSpec tests to test my app, but I've stumbled on several problems that I can't find any solution. 1) I am trying to test the update action. Here is my code:
it "email is a new one" do
put :update, id: @user, user: FactoryGirl.attributes_for(:user, :email=>"[email protected]")
@user.reload
@user.email.should == "[email protected]"
puts @user.email
end
Here is the UsersController update action:
def update
@user = User.find(params[:id])
respond_to do |format|
if @user.update_attributes(params[:user])
format.html { redirect_to edit_user_path(@user), :notice => "Your settings were successfully updated."}
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
Here is the error:
Failure/Error: @user.email.should == "[email protected]"
expected: "[email protected]"
got: "[email protected]" (using ==)
It's obvious that the test hasn't changed the email of the user. I took the update action tutorial from here: http://everydayrails.com/2012/04/07/testing-series-rspec-controllers.html . Where I could find the solution?
Could @user.update_attributes(params[:user])
be failing for a validation reason?
Also, you could ensure that your test and the controller method are interacting with the same ruby object. That's been a gotcha for me in the past. The way I do it is to stub the find
method on the class.
it "email is a new one" do
User.stubs(:find).returns(@user)
put :update, id: @user, user: FactoryGirl.attributes_for(:user, :email=>"[email protected]")
@user.reload
@user.email.should == "[email protected]"
puts @user.email
end
This ensures that you're talking about not only the same record, but the same object during the test.
Lastly, I would argue that your test is doing very much for you. You're basically testing update_attributes
, which is a core feature and thoroughly tested already. I would focus on testing the controller behavior. Something like this:
let(:user) { FactoryGirl.create(:user) }
describe "PUT #update" do
before(:each) {
User.stubs(:find).returns(user)
}
it "should redirect to the user path on succesful save" do
user.should_receive(:update_attributes).and_return true
put :update, user, {}
response.should redirect_to(edit_user_path(user))
end
it "should render the edit screen again with errors if the model doesn't save" do
user.should_receive(:update_attributes).and_return false
put :update, user, {}
response.should render_template("edit")
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With