我正在测试我的用户模型并研究FactoryGirl的工作原理。当我在 user_spec.rb :
中执行此操作时before(:each) do
@user = User.new(username: 'ExampleUser', email: 'user@example.com', timezone: 'Eastern Time (US & Canada)', password: 'example')
end
一切都过去了,但如果我这样做了:
before(:each) do
@user = FactoryGirl.create(:user)
end
它未通过测试以查看用户的用户名和电子邮件是否已被删除。
1) User when username is already taken
Failure/Error: it { should_not be_valid }
expected valid? to return false, got true
# ./spec/models/user_spec.rb:151:in `block (3 levels) in <top (required)>'
2) User when email address is already taken
Failure/Error: it { should_not be_valid }
expected valid? to return false, got true
# ./spec/models/user_spec.rb:142:in `block (3 levels) in <top (required)>'
Finished in 1.8 seconds
29 examples, 2 failures
这些是测试:
describe 'when email address is already taken' do
before do
user_with_same_email = @user.dup
user_with_same_email.email = @user.email.upcase
user_with_same_email.save
end
it { should_not be_valid }
end
describe 'when username is already taken' do
before do
user_with_same_username = @user.dup
user_with_same_username.username = @user.username.upcase
user_with_same_username.save
end
it { should_not be_valid }
end
有人可以解释一下吗?我以为FactoryGirl想让我像User.new
一样使用它,这是我的第一个有效的例子。
答案 0 :(得分:1)
FactoryGirl.create
实际创建了记录,而User.new
仅实例化模型,但实际上并未保存记录。
如果您只想实例化模型,则应使用FactoryGirl.build
:
before(:each) do
@user = FactoryGirl.build(:user)
end
有关详细信息,请参阅documentation。
因此,我认为当前代码发生的情况是,当您使用FactoryGirl.create
创建用户时,它实际上保存了记录而没有验证问题(因为尚未创建副本)。当您使用user_with_same_email.save
的同一电子邮件保存用户时,它实际上并不保存该用户,但您没有看到。然后,当您检查原始用户是否有效时,它会显示是,因为您在尝试(并且未能)创建副本之前已经保存了它。
有意义吗?无论如何只需切换到FactoryGirl.build
,两个测试都应该通过。
答案 1 :(得分:1)
通常在使用具有validates_uniqueness_of
的Factory Girl测试字段时,最好使用sequence。
使用序列时,每次使用FactoryGirl.create(:user)
创建记录时,用户名始终是唯一的。这使您可以使用数据库中的“真实”记录,而无需手动纠正冲突的值。
factory :user do
sequence :username do |n}
"user_#{n}"
end
end
注意:我不喜欢测试尚未添加到数据库中的记录的想法。我想不出有什么可能成为问题的坚实理由。我能想到的唯一问题是你将无法测试关联。
我一直注意到的其他问题是您使用before
块并创建实例变量。在RSpec中,有一个名为let
的方法将在需要时创建变量。
这会使您的user_spec.rb
文件正常工作。
describe User do
let(:user) { create(:user, :first_name => "John", :last_name => "Doe") }
it "should get full name" do
user.full_name.should == "John Doe"
end
end
let
还有一个bang方法,可以创建变量,无论它是否在it
块中使用。