如何在 Rspec/Capybara 测试中访问 FactoryGirl 生成的用户的虚拟属性?
How do I access a virtual attribute on a FactoryGirl-generated user in an Rspec/Capybara test?
在自学 Ruby 和 Rails 的过程中,我目前正在构建一个紧密基于 Hartl tutorial 的用户系统;此时的主要区别是我使用 Rspec/Capybara 而不是 TestUnit 对其进行测试。到目前为止,大多数事情都相当简单,但我一直在测试密码重置时遇到这个问题。
当我手动测试密码重置时,它们完全按预期工作。因此,我很确定问题出在 Rspec、Capybara 和 FactoryGirl 之间。
一直失败的规范代码是当我想访问忘记密码的时候link:
# password_resets_spec.rb
visit(edit_password_reset_path(spec_user.reset_token, email: spec_user.email))
它给了我:
ActionController::UrlGenerationError:
No route matches {:action=>"edit", :controller=>"password_resets", :email=>"john2@example.com",
:format=>nil, :id=>nil} missing required keys: [:id]
密码重置是一个(部分)资源,它们的 id 是用户的 reset_token
。
spec_user
由FactoryGirl生成:
#password_resets_spec.rb
let(:spec_user){ FactoryGirl.create :user }
相关的 :user
工厂没有设置 reset_token
但是当我用一个设置的工厂尝试它时,重置表单没有正确设置令牌,并且与生成的摘要。这是设置两者的代码:
# user.rb
def create_reset_digest
self.reset_token = User.new_token
update_attribute(:reset_digest, User.digest(reset_token))
update_attribute(:reset_sent_at, Time.zone.now)
end
我可以通过使用设置 reset_token
的工厂来绕过上述错误,但是用于路由的令牌与保存的摘要不匹配,测试的下一步失败。
到目前为止,我的结论是我误解了虚拟属性的处理方式,因为令牌是虚拟的,而摘要保存到数据库中。我怀疑我在规范中为我的路线获得的 reset_token
与生成摘要所涉及的不同,不知何故。
如果能帮助理解这里发生的事情,我们将不胜感激! :)
您收到路由错误,因为 reset_token
没有值;在这种情况下是您的 ID。
您可以在工厂创建的对象上设置/分配虚拟属性。只需将值传递给工厂即可:
let(:spec_user){ FactoryGirl.create :user, reset_token: "some value"}
但是,对于您的用例,我猜您还需要将散列值存储在数据库中。 pasword_resets#edit
可能通过散列传入的 reset_token
.
来查找用户记录
因此,在您的规范中:
require 'spec_helper'
describe "PasswordResets" do
describe "#edit" do
it "looks up the user and provides a form to reset the password" do
# Generate the token in advance, so you can set the digest on the user
reset_token = User.new_token
# Create your user with the digest
spec_user = FactoryGirl.create(:user, reset_token: reset_token, reset_digest: User.digest(reset_token), reset_sent_at: Time.zone.now)
# Now visit path with an actual value for reset_tokeb
visit(edit_password_reset_path(spec_user.reset_token, email: spec_user.email))
end
end
end
在自学 Ruby 和 Rails 的过程中,我目前正在构建一个紧密基于 Hartl tutorial 的用户系统;此时的主要区别是我使用 Rspec/Capybara 而不是 TestUnit 对其进行测试。到目前为止,大多数事情都相当简单,但我一直在测试密码重置时遇到这个问题。
当我手动测试密码重置时,它们完全按预期工作。因此,我很确定问题出在 Rspec、Capybara 和 FactoryGirl 之间。
一直失败的规范代码是当我想访问忘记密码的时候link:
# password_resets_spec.rb
visit(edit_password_reset_path(spec_user.reset_token, email: spec_user.email))
它给了我:
ActionController::UrlGenerationError: No route matches {:action=>"edit", :controller=>"password_resets", :email=>"john2@example.com", :format=>nil, :id=>nil} missing required keys: [:id]
密码重置是一个(部分)资源,它们的 id 是用户的 reset_token
。
spec_user
由FactoryGirl生成:
#password_resets_spec.rb
let(:spec_user){ FactoryGirl.create :user }
相关的 :user
工厂没有设置 reset_token
但是当我用一个设置的工厂尝试它时,重置表单没有正确设置令牌,并且与生成的摘要。这是设置两者的代码:
# user.rb
def create_reset_digest
self.reset_token = User.new_token
update_attribute(:reset_digest, User.digest(reset_token))
update_attribute(:reset_sent_at, Time.zone.now)
end
我可以通过使用设置 reset_token
的工厂来绕过上述错误,但是用于路由的令牌与保存的摘要不匹配,测试的下一步失败。
到目前为止,我的结论是我误解了虚拟属性的处理方式,因为令牌是虚拟的,而摘要保存到数据库中。我怀疑我在规范中为我的路线获得的 reset_token
与生成摘要所涉及的不同,不知何故。
如果能帮助理解这里发生的事情,我们将不胜感激! :)
您收到路由错误,因为 reset_token
没有值;在这种情况下是您的 ID。
您可以在工厂创建的对象上设置/分配虚拟属性。只需将值传递给工厂即可:
let(:spec_user){ FactoryGirl.create :user, reset_token: "some value"}
但是,对于您的用例,我猜您还需要将散列值存储在数据库中。 pasword_resets#edit
可能通过散列传入的 reset_token
.
因此,在您的规范中:
require 'spec_helper'
describe "PasswordResets" do
describe "#edit" do
it "looks up the user and provides a form to reset the password" do
# Generate the token in advance, so you can set the digest on the user
reset_token = User.new_token
# Create your user with the digest
spec_user = FactoryGirl.create(:user, reset_token: reset_token, reset_digest: User.digest(reset_token), reset_sent_at: Time.zone.now)
# Now visit path with an actual value for reset_tokeb
visit(edit_password_reset_path(spec_user.reset_token, email: spec_user.email))
end
end
end