Rails
RSpec
test
FactoryGirl

FactoryGirl 外部キーのuniquenessテストで手こずったこと

まず、belongs_to, has_many の関係で外部キーに関するテストを行いたかった。。。。が

書いていたコード

model

class UserName < ApplicationRecord
  belongs_to :user

facrtory

FactoryGirl.define do
  factory :user_name do
    name 'hogehoge'
    user_id 1
  end
end

model_spec

context 'uniqueness' do
 subject { create(:user_background) }
 it { is_expected.to validate_uniqueness_of(:user_id) }
end

error

.F

Failures:

  1) UserBackground#create should have a unique user_id
     Failure/Error: should validate_uniqueness_of(:user_id)

     Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher::ExistingRecordInvalid:
       validate_uniqueness_of works by matching a new record against an
       existing record. If there is no existing record, it will create one
       using the record you provide.

       While doing this, the following error was raised:

         PG::NotNullViolation: ERROR:  null value in column "user_id" violates not-null constraint
         DETAIL:  Failing row contains (17, null, null, 2017-12-06 20:38:00.990373, 2017-12-06 20:38:00.990373).
         : INSERT INTO "user_backgrounds" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"

       The best way to fix this is to provide the matcher with a record where
       any required attributes are filled in with valid values beforehand.
     # ./spec/models/user_background_spec.rb:18:in `block (3 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # PG::NotNullViolation:
     #   ERROR:  null value in column "user_id" violates not-null constraint
     #   DETAIL:  Failing row contains (17, null, null, 2017-12-06 20:38:00.990373, 2017-12-06 20:38:00.990373).
     #   ./spec/models/user_background_spec.rb:18:in `block (3 levels) in <top (required)>'

原因

どうやら、user_id は外部キーであるために直接いれてはいけないらしいです。
ということで、アドバイスをもらいつつこんな感じにもしましたがだめでした。

facrtory

FactoryGirl.define do
  factory :user_name do
    name 'hogehoge'
    user_id user
  end
end

解決策

こちらを参考にさせてもらいもらったところこんな感じでいけました。
http://shim0mura.hatenadiary.jp/entry/2014/06/29/002102

factory

FactoryGirl.define do
  factory :user_name do
    image_url { Faker::File.file_name('path/to') }
    association :user, factory: :user
  end
end

model_spec

context 'uniqueness' do
  subject { create(:user_background) }
  it { is_expected.to validate_uniqueness_of(:user_id) }
end

まとめ

belongs_to, has_many が関連するモデルをテストする場合は

model_spec

belongs_to :user

 association :user, factory: :user

has_many :user

  users {[
      FactoryGirl.create(:user)
    ]}

でassociationをくんであげると善きみたいですね。