Rspec:验证失败:名称已被占用

shr*_*roy 6 ruby tdd rspec ruby-on-rails factory-bot

运行我的规范时,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>'
Run Code Online (Sandbox Code Playgroud)

如果没有相关programcampaign工厂,我的测试运行细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
Run Code Online (Sandbox Code Playgroud)

我的相关模型..

Class Campaign < ActiveRecord::Base
    belongs_to :program
    validates :program, presence: true

    belongs_to :plan
end

Class Program < ActiveRecord::Base
    has_many :campaigns
end
Run Code Online (Sandbox Code Playgroud)

这肯定与使用 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
Run Code Online (Sandbox Code Playgroud)

更新 #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
Run Code Online (Sandbox Code Playgroud)

在它达到我的规格之前发生了一些事情,我相信答案是错误所指的lint!我不太熟悉“lint”,因为我在博客之后设置了我的工厂。我检查了文档,似乎我已经正确设置了它......但是,它在清理数据库之前以及运行任何规范之前通过我的验证运行我的工厂。

当我想validates :program, presence: true在规范中实例化它时,这是一个问题。'FactoryGirl.lint' 打断了我的测试,让我知道这can't be blank正是我希望工厂看起来的样子。到目前为止,我能想到的唯一解决方案是禁用,lint因为我可以让我的规范在禁用它的情况下运行..但是现在我对它有了更多的了解,我可以看到它如何变得非常有用。

这种情况有双赢的局面吗?我还能lint在保留验证和关联的同时按照我需要的方式保留它们吗?

下面就来看看我的规格/支持/ 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
Run Code Online (Sandbox Code Playgroud)

iva*_*van 5

是否Program验证其name属性的唯一性?如果是这样,您需要重新定义program工厂以为其生成的每个实例生成唯一名称。

factory :program do
  sequence(:name) { |n| "Caspian Star #{n}" }
end
Run Code Online (Sandbox Code Playgroud)

或者,如果你有一个特定的程序,你已经播种(或以其他方式保证存在)和访问它的方法,你可以在声明关联时使用块

factory :campaign do |x|
  ...
  program { Program.some_program }
end
Run Code Online (Sandbox Code Playgroud)