RSpec测试PUT更新动作

我正在尝试编写一些RSpec测试来测试我的应用程序,但我偶然发现了一些我找不到任何解决方案的问题。 1)我正在尝试测试更新操作。 这是我的代码:

it "email is a new one" do put :update, id: @user, user: FactoryGirl.attributes_for(:user, :email=>"a@bc") @user.reload @user.email.should == "a@bc" puts @user.email end 

这是UsersController更新操作:

  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 

这是错误:

  Failure/Error: @user.email.should == "a@bc" expected: "a@bc" got: "user16@example.com" (using ==) 

很明显,测试没有改变用户的电子邮件。 我从这里获取了更新操作教程: http : //everydayrails.com/2012/04/07/testing-series-rspec-controllers.html 。 哪里可以找到解决方案?

@user.update_attributes(params[:user])是否因validation原因而失败?

此外,您可以确保您的测试和控制器方法与同一个ruby对象进行交互。 这对我来说过去很困难。 我这样做的方法是在类上存根find方法。

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

这可以确保您在测试期间不仅讨论相同的记录,而且讨论相同的对象。


最后,我认为你的测试对你来说非常重要。 您基本上是在测试update_attributes ,这是一项核心function,已经过全面测试。 我将专注于测试控制器行为。 像这样的东西:

 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 

我认为put的论点是不正确的。

putgetdeletepost接受三个参数。 第一个是路径,第二个是params,第三个是选项。

在你的代码中你把两个参数作为两个参数,这是不正确的。

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

所以,改成它

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

可是等等! 您的代码将通过上述更改工作,但您当前的代码中存在安全漏洞。 确保您将添加权限检查控制器代码。 例如

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