Ruby on rails 当我以这种方式使用FactoryGirl时,为什么我的测试失败?
我正在测试我的用户模型,研究FactoryGirl是如何工作的。当我在我的用户规范rb中执行此操作时:Ruby on rails 当我以这种方式使用FactoryGirl时,为什么我的测试失败?,ruby-on-rails,ruby-on-rails-3,factory-bot,rspec-rails,Ruby On Rails,Ruby On Rails 3,Factory Bot,Rspec Rails,我正在测试我的用户模型,研究FactoryGirl是如何工作的。当我在我的用户规范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
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
有人能解释一下吗?我认为FactoryGirl应该让我像使用用户一样使用它。new,这是我第一个有效的示例。
FactoryGirl.create
实际上创建了记录,而User.new只实例化了模型,但实际上并没有保存记录
如果只想实例化模型,则应使用FactoryGirl.build
:
before(:each) do
@user = FactoryGirl.build(:user)
end
有关详细信息,请参阅
因此,我认为当前代码的情况是,当您使用FactoryGirl.create
创建用户时,它实际上保存了记录,没有任何验证问题(因为尚未创建副本)。当您使用user\u with\u same\u email.save
以相同的电子邮件保存用户时,它实际上不会保存该用户,但您看不到。然后,当您检查原始用户是否有效时,它会说是,因为您在尝试(但失败)创建副本之前已经保存了它
有道理吗?无论如何,只要切换到
FactoryGirl.build
,两个测试都应该通过。通常,当使用Factory Girl测试一个字段时,该字段具有验证的唯一性时,最好使用
使用序列时,每次使用FactoryGirl.create(:user)
创建记录时,用户名将始终是唯一的。这允许您处理数据库中的“真实”记录,而无需手动更正冲突值
factory :user do
sequence :username do |n}
"user_#{n}"
end
end
注意:我不喜欢测试尚未添加到数据库中的记录。我想不出任何确切的理由来解释为什么这会成为一个问题。我能想到的唯一问题是,您将无法测试关联
我一直注意到的另一个问题是在
块之前使用,并创建实例变量。在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
块中使用。您是否在每个测试示例之前使用类似数据库清理器()的东西重置DB?我明白您所说的创建和所有,但在逻辑上没有意义。FactoryGirl.create(:user)应该先在数据库中生成user.first,然后blah=@user.dup,他完成了他的任务,然后blah.save!应该抛出一个错误。如果不是,这个工厂女孩有什么好处?我知道我和我们的OP一样也有这个问题,这对我来说毫无意义,让我发疯。我的意思是,在现实生活中,他可以在控制台中执行,他会得到一个错误,所以他的测试应该反映出这一点,依我看。我不明白你为什么说,原始文件保存后会检查其有效性?我认为它是@user=FG.create#保存好。b=@user.dup#复制相同的对象。b、 email=@user.email.upcase#将其更改,但仍保持不变;b、 救命代码>应引发验证错误。我只是在控制台中尝试了这一点,但没有使用FG.create,而是使用了my User.first。@pjammer我想您可能混淆了规范中验证错误的检查内容。在中{should\u not\u valid}
主题是@user
,而不是user\u with\u same\u email
或user\u with\u same\u username
<代码>废话。保存
会抛出一个错误,但他没有发出砰的一声就调用了它,所以它不会抛出错误,只是无法保存(静默)。重复一下,b.save
会抛出一个错误,但他正在调用b.save
,它会无声地失败。那么他的测试也是错误的吗?你说得对,我对it行的理解不够,但他不想确保用户名相同的用户无效吗?这样测试工厂有什么好处?
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