2

我已经使用bcrypt-ruby和组合了一个带有用户身份验证的基本应用程序has_secure_password。结果本质上是Rails 教程中应用程序的准系统版本。换句话说,我有一个 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
4

3 回答 3

7

对于设计用户,请#valid_password?改用:

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

信用:瑞恩比格

于 2016-08-28T04:29:06.617 回答
2

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

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

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

于 2013-08-04T02:45:13.683 回答
2

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

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

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

于 2013-08-04T04:13:31.560 回答