在运行我的规范时,我在FactoryGirl
错误之前停止了,之后rspec甚至可以遍历它们。
Finished in 0.18709 seconds (files took 1.57 seconds to load)
0 examples, 0 failures
/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/factory_girl-4.5.0/lib/factory_girl/linter.rb:14:in `lint!': The following factories are invalid: (FactoryGirl::InvalidFactoryError)
* program - Validation failed: Name has already been taken (ActiveRecord::RecordInvalid)
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/factory_girl-4.5.0/lib/factory_girl/linter.rb:4:in `lint!'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/factory_girl-4.5.0/lib/factory_girl.rb:59:in `lint'
from /spec/support/factory_girl.rb:9:in `block (2 levels) in <top (required)>'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/example.rb:333:in `instance_exec'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/example.rb:333:in `instance_exec'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/hooks.rb:357:in `run'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/configuration.rb:1559:in `block in run_hooks_with'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/configuration.rb:1559:in `each'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/configuration.rb:1559:in `run_hooks_with'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/configuration.rb:1525:in `with_suite_hooks'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/runner.rb:109:in `block in run_specs'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/reporter.rb:62:in `report'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/runner.rb:108:in `run_specs'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/runner.rb:86:in `run'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/runner.rb:70:in `run'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/lib/rspec/core/runner.rb:38:in `invoke'
from /.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.2.3/exe/rspec:4:in `<top (required)>'
from /.rbenv/versions/2.2.2/bin/rspec:23:in `load'
from /.rbenv/versions/2.2.2/bin/rspec:23:in `<main>'
如果program
工厂中没有关联的campaign
,我的测试就可以15 examples, 2 failures
运行。
这是我的工厂..
FactoryGirl.define do
factory :campaign do |x|
x.sequence(:name) { |y| "Q6 201#{y}" }
x.sequence(:comment) { |y| "JIRA OI-6#{y}" }
channels ["Folder", "Fax"]
program
end
factory :program do
name "Caspian Star"
end
factory :plan do
name "Third Storm Connect"
end
end
我的相关模型..
Class Campaign < ActiveRecord::Base
belongs_to :program
validates :program, presence: true
belongs_to :plan
end
Class Program < ActiveRecord::Base
has_many :campaigns
end
这肯定与使用Campaign设置相关程序有关,但我无法弄清楚如何正确执行。我的目的是不创建program
的多个实例,而是让广告系列与现有广告相关联 - 或者我通过FactoryGirl创建的广告系列。
使用FactoryGirl的association :program
方法时,我收到同样的错误。我对program
工厂的名称似乎并不重要。我在运行后也使用DatabaseCleaner
清除测试数据库。
我目前正在尝试对validates :program, presence true
进行测试,但会继续在圈子中运行。
非常感谢任何帮助。
更新
以下是所要求的规格。
describe "Relationships" do
it { should belong_to :program }
...some unrelated relationship specs..
end
describe "Validations" do
it { should validate_presence_of :name }
it { should validate_uniqueness_of :name }
it { should serialize :channels }
it { should validate_presence_of :comment }
it { should validate_presence_of :program }
end
it "serializes column into Array" do
obj = build(:campaign)
obj.channels = [1,2,3]
obj.save!
expect(obj.reload.channels).to eq [1, 2, 3]
end
it 'validates associated campaign' do
campaign = build(:campaign)
expect(campaign.save).to be_valid?
expect(campaign.errors).to eq "You need to choose a Program."
end
end
更新#2
在尝试下面的一些答案后,我可以确认sequence
无法解决错误。但是,当我完全删除FactoryGirl关联但实例化规范中的关联时 - 我收到错误Validation failed: Program can't be blank
。请注意,我的规格仍未运行..
Finished in 0.19413 seconds (files took 1.54 seconds to load)
0 examples, 0 failures
在达到我的规格之前还有一些事情发生了,我相信答案就是错误所指的lint!
我不太熟悉&#39; lint&#39;,因为我设置了我的工厂跟随博客。我检查了文档,似乎我已正确设置...但是,它在数据库清理之前以及运行任何规范之前通过我的验证运行我的工厂。
当我想validates :program, presence: true
并在规范中实例化时,这是一个问题。 &#39; FactoryGirl.lint&#39;中断了我的测试,让我知道它can't be blank
,这正是我想要工厂看起来的样子。到目前为止,我能想到的唯一解决方案是禁用lint
,因为我可以让我的规格在禁用的情况下运行..但现在我了解更多,我可以看到它如何变得非常有用。
这种情况是否存在双赢局面?我可以按照lint
的方式保留验证和关联吗?
在这里查看我的 spec / support / factory_girl.rb ,其中lint
存在..
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.before(:suite) do
begin
DatabaseCleaner[:active_record].strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.start
FactoryGirl.lint
ensure
DatabaseCleaner.clean
end
end
end
答案 0 :(得分:4)
Program
是否验证了name
属性的唯一性?如果是这样,您需要重新定义program
工厂,为其生成的每个实例生成唯一的名称。
factory :program do
sequence(:name) { |n| "Caspian Star #{n}" }
end
或者,如果你有一个特定的程序,你已经播种(或保证存在)以及一种访问它的方法,你可以在声明关联时使用一个块
factory :campaign do |x|
...
program { Program.some_program }
end
答案 1 :(得分:3)
您可能正在实例化两个program
,并且您工厂中的程序名称是硬编码的。制作一个序列(就像你为广告系列所做的那样),你会很高兴。
*更新* 如果您希望广告系列具有相同的程序,则必须从Campaign的工厂中删除程序分配,并在规范中明确传递。像这样:
FactoryGirl.define do
factory :campaign do |x|
x.sequence(:name) { |y| "Q6 201#{y}" }
x.sequence(:comment) { |y| "JIRA OI-6#{y}" }
channels ["Folder", "Fax"]
# no more program here
end
factory :program do
name "Caspian Star"
end
factory :plan do
name "Third Storm Connect"
end
end
你的规格:
let(:program) { FactoryGirl.create(:program) }
let(:campaign) { FactoryGirl.build(:campaign, program: program) }
describe "Relationships" do
it { campaign.should belong_to :program }
...some unrelated relationship specs..
end
describe "Validations" do
it { campaign.should validate_presence_of :name }
it { campaign.should validate_uniqueness_of :name }
it { campaign.should serialize :channels }
it { campaign.should validate_presence_of :comment }
it { campaign.should validate_presence_of :program }
end
或者,上面的代码允许您按原样离开工厂并根据需要覆盖程序实例。
在您的规范中,您使用build
+ save!
构建对象,而您应该使用FactoryGirl.create
:
it "serializes column into Array" do
campaign = FactoryGirl.create(:campaign, channels: [1,2,3])
expect(campaign.channels).to eq [1, 2, 3]
end
答案 2 :(得分:1)
我不确定这是否与您遇到的问题相同,但我遇到了类似的错误,问题是我在规范中调用了Model.create!
方法(失败并显示验证错误消息而不是静默失败)。一旦我删除了爆炸!
,一切都正常运行。
答案 3 :(得分:1)
我遇到了这个问题,因为我之前创建了一个具有相同名称的记录,因此我必须运行:
rails db:setup
然后我摆脱它,它又开始工作了。
答案 4 :(得分:0)
我不知道这个问题是否已经解决。考虑到这是一个非常古老的问题。我自己也很努力地解决这个问题。添加我的答案只是为了文档。
我在我的工厂中为ModelB使用了序列,这对错误没有帮助。我也尝试过database_cleaner。仍然没有成功。
Joshua Clayton在这篇文章中解释了错误的原因 https://github.com/thoughtbot/factory_girl/issues/523
我所理解的是,即使我使用了序列,我在使用工厂之前的测试中创建了我的ModelB。 Factorygirl无法跟踪序列中的记录。因此这个名字已经被采用了。
我怀疑以下代码导致了这一切。
class ModelA
before_create :create_model_b
...
作为解决问题的快速而肮脏的方法,我更改了ModelB的工厂以使序列偏移大量。
FactoryGirl.define do
factory :model_b do
sequence(:name){|n| "name_#{n+1000}"}
...
end
end
有效!! 似乎是一个相当愚蠢的解决方案,但我的规格现在都是绿色的:)