RSpec test PUT update action

I am trying to write some RSpec tests to test my application, but I came across several problems that I cannot find. 1) I'm trying to check the update action. Here is my code:

it "email is a new one" do put :update, id: @user, user: FactoryGirl.attributes_for(:user, :email=>" a@b.c ") @user.reload @user.email.should == " a@b.c " 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 == " a@b.c " expected: " a@b.c " got: " user16@example.com " (using ==) 

Obviously, the test did not change the user's email address. I took the upgrade tutorial from here: http://everydayrails.com/2012/04/07/testing-series-rspec-controllers.html . Where can I find a solution?

+4
source share
2 answers

Can @user.update_attributes(params[:user]) fail due to validation?

In addition, you can verify that your test and controller method interact with the same ruby ​​object. It was for me in the past. The way I do this is to stub the find method in the class.

 it "email is a new one" do User.stubs(:find).returns(@user) put :update, id: @user, user: FactoryGirl.attributes_for(:user, :email=>" a@b.c ") @user.reload @user.email.should == " a@b.c " puts @user.email end 

This ensures that you are talking not only about the same record, but about the same object during the test.


Finally, I would say that your test is very much for you. Basically you are testing update_attributes , which is the main function and fully tested. I would focus on testing controller behavior. Something like that:

 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 
+5
source

I think the argument for put incorrect.

put , get , delete , post take three arguments. The first is the path, the second is the parameters, and the third are the options.

In the code, you put two parameters as two arguments, this is not true.

 put :update, id: @user, user: FactoryGirl.attributes_for(:user, :email=>" a@b.c ") 

So change it to

 put :update, {id: @user, user: FactoryGirl.attributes_for(:user, :email=>" a@b.c ")} 

But wait! your code will work with the change above, but there is a security hole in your current code. Make sure you add authorization checking to the controller code. for instance

 return unauthorized unless @user == current_user || current_user.role == "admin" 
+3
source

Source: https://habr.com/ru/post/1488945/


All Articles