如何测试成功更改密码?

时间:2012-10-16 17:01:23

标签: ruby-on-rails ruby-on-rails-3 rspec rspec-rails railstutorial.org

我使用bcrypt-rubyhas_secure_password将基本应用程序与用户身份验证放在一起。结果基本上是来自Rails Tutorial的应用程序的准系统版本。换句话说,我有一个RESTful用户模型以及登录和注销功能。

作为编辑用户信息的测试的一部分,我编写了一个更改密码的测试。虽然更改密码在浏览器中工作正常,但我的测试不会通过。

subject { page }

describe "successful password change"
  let(:new_password) { "foobaz" }
  before do
    fill_in "Password",               with: new_password
    fill_in "Password Confirmation",  with: new_password
    click_button "Save changes"
  end

  specify { user.reload.password.should == new_password }
end

显然,我在这里误解了一些基本细节。

简而言之:

1)为什么上面的代码无法正常工作?更改密码功能在浏览器中有效。同时,rspec继续在上面的最后一行重新加载旧密码。然后测试失败了。

2)测试密码更改的更好方法是什么?

修改

初始密码设置为foobar时,错误消息为:

Failure/Error: specify { user.reload.password.should == new_password }
   expected: "foobaz"
        got: "foobar" (using ==)

基本上,看起来before块实际上并没有保存新密码。

作为参考,相关的控制器动作如下:

def update
  @user = User.find(params[:id])
  if @user.update_attributes(params[:user])
    flash[:success] = "Profile Updated"
    sign_in @user
    redirect_to root_path
  else
    render 'edit'
  end
end

3 个答案:

答案 0 :(得分:6)

对于Devise用户,请改用#valid_password?

expect(user.valid_password?('correct_password')).to be(true)

信用:Ryan Bigg

答案 1 :(得分:2)

这里不太令人满意的解决方案是使用#authenticate提供的bcrypt-ruby方法编写测试。

specify { user.reload.authenticate(new_password).should be_true }

虽然这不是一个合适的集成测试,但它会让我们变绿。

答案 2 :(得分:2)

您的回答(使用authenticate)是正确的方法;你应该对此感到满意。您希望比较模型中密码的散列版本而不是@password(通过attr_accessor)。请记住,您要保存哈希值,而不是实际密码。

您的测试中的user是该用户在内存中的副本。运行测试时,update方法会在内存中加载该用户的不同副本,并更新其保存到db的密码哈希值。你的副本没有变化;这就是为什么你想重新加载来从数据库中获取更新的数据。

密码字段不存储在数据库中,而是存储为散列,因此新的散列从数据库重新加载,但您正在比较user实例中的@password的短暂状态的encrypted_pa​​ssword。