0

特征

用户有一个配置文件并且应该能够更新它。


问题

我更新了配置文件,例如将名称更改为“Homer Simpson”,但所有断言都失败了,因为数据库记录似乎没有更新。

我似乎无法获得更新的属性:

 Failure/Error: expect(subject.current_user.first_name).to eq('Homer')

   expected: "Homer"
        got: "Lew"

   (compared using ==)
 # ./spec/controllers/registrations_controller_spec.rb:67:in `block (3 levels) in <top (required)>'

注意我已经尝试@user.reloadsubject.current_user.reload

规格仍然没有通过。


代码

我在用:

  • 导轨 (4.0.0)
  • 设计(3.0.3)
  • rspec-rails (2.14.0)
  • 水豚 (2.1.0)
  • factory_girl (4.2.0)
  • database_cleaner (1.1.1)

我已经检查过:

registrations_controller_spec.rb

describe "User Profiles" do
  login_user

  it "Update - changes the user's attributes" do
    put :update, id: @user, user: attributes_for(:user, first_name: 'Homer')
    @user.reload
    expect(@user.first_name).to eq('Homer') # FAILS
  end
end

我曾尝试在此 Stackoverflow 线程中@user进行交换: “设计 Rspec 注册控制器测试在更新时失败,就好像它正在尝试确认电子邮件地址一样”subject.current_user

  put :update, id: subject.current_user, user: attributes_for(:user, first_name: 'Homer')
  subject.current_user.reload
  expect(subject.current_user.first_name).to eq('Homer') # Still FAILS

但它仍然失败。

是控制器的问题吗?我通过current_user.id而不是通过找到用户 via params[:id]

注册控制器.rb

def update
  @user = User.find(current_user.id)
  email_changed = @user.email != params[:user][:email]
  password_changed = !params[:user][:password].blank?

  if email_changed or password_changed
    successfully_updated = @user.update_with_password(user_params)
  else
    successfully_updated = @user.update_without_password(user_params)
  end

  if successfully_updated
    sign_in @user, bypass: true # Sign in the user bypassing validation in case his password changed
    redirect_to user_profile_path, notice: 'Profile was successfully updated.'
  else
    render "edit"
  end
end

controller_macros.rb - 定义login_user助手

module ControllerMacros
  def login_user    
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:user]
      @user = FactoryGirl.create(:user)
      @user.confirm!
      sign_in @user
    end
  end
end

我的集成规范通过了。我在控制器中缺少什么?

4

3 回答 3

2

我的回答可以解决您的问题,但不能直接修复您代码中的错误。为此,我需要编写更多的测试和动手调试,我没有那么多经验来通过只读来解决它:)

我不建议您像有问题的那样覆盖 Devise 的 RegistrationsController。与原始代码相比,您的代码至少缺少两点:

  1. 没有 current_user 对象的副本。在实际应用程序中,current_user 将通过提交不好的表单来注销。

  2. 缺乏对参数的清理

和剩下的错误。

我的建议是直接使用 Devise 的方法,因为你的代码没有什么特别之处,也不需要重写full code

class RegistrationsController < Devise::RegistrationsController
  def update
  end
  # Or even without this method.
end

就这样。

无需密码

def update
  params.merge!(password: current_user.password) if params[:password].blank?
  super
end

对于测试,只需编写一些随意的集成测试。设计具有全面的功能测试,因此无需重复。

于 2013-09-25T15:48:08.110 回答
0

尝试assigns

it "Update - changes the user's attributes" do
  put :update, id: @user, user: attributes_for(:user, first_name: 'Homer')
  homer = assigns(:user)
  @user.reload
  expect(homer.first_name).to eq('Homer')
end

更新:根据比利陈的评论,这应该正确测试名称正在更新

it "Update - changes the user's attributes" do
  put :update, id: @user, user: attributes_for(:user, first_name: 'Homer')
  homer = assigns(:user)
  @user.reload
  #expect(homer.first_name).to eq('Homer') Peter and Billy are right, this only tests
  # that the attribute was actually assigned, not that the update was successful
  expect(@user.first_name).to eq(homer.first_name)
  #however this test that the users updated `first_name` matches the attribute 
  #in the test 
end

注意

我的这个答案基于我几个月前经历的 Michael Hartl 教程——他使用了这种方法,我相信他解释了原因——尽管我目前没有屏幕投射。我稍后会查一下。

视频

这是视频——它的质量非常低,因为我刚刚使用了 quicktime 的屏幕记录——而且一开始有一些残酷的反馈循环,所以在开始的几秒钟内让你的电脑静音。

于 2013-09-25T14:38:08.050 回答
0

回答

感谢大家的建议,这些建议帮助我整理代码并找到问题所在。

失败原因:默认出厂包含的参数包括电子邮件和密码,因此控制器测试不断尝试更改用户的密码。

具体来说,我在registrations_controller_spec.rb中更改了这行代码

put :update, id: @user, user: attributes_for(:user, first_name: 'Homer')

至:

patch :update, id: @user, user: attributes_for(:user_params, first_name: 'Homer', last_name: 'Simpson')

然后我不得不更新我的工厂,所以我可以使用:user_params更新:

FactoryGirl.define do

  factory :user do
    first_name          { Faker::Name.first_name }
    last_name           { Faker::Name.last_name }
    sequence(:username) { |n| "user-#{n}" }
    email               { Faker::Internet.email }
    password            { Faker::Lorem.characters(8) }
  end

  factory :user_params, class: :user do
    first_name     { Faker::Name.first_name }
    last_name      { Faker::Name.last_name }

    factory :user_params_with_email, class: :user do
      email        { Faker::Internet.email }
    end

    factory :user_params_with_password, class: :user do
      password    { Faker::Lorem.characters(8) }
    end
  end

end

感谢所有提出建议的人。它帮助我解开我的代码,@billy-chan 正确地指出了我修复的问题。

  • 未清理参数(正在完成 rails4 升级)
  • 其他杂项 错误

学过的知识

比较进出控制器的参数。

我的集成测试通过了,因为我没有尝试更改电子邮件或密码。

于 2013-09-26T09:23:13.800 回答