Skip to content

Instantly share code, notes, and snippets.

@jooeycheng jooeycheng/snippets.md
Last active Mar 18, 2019

Embed
What would you like to do?

The RSpec

# spec/models/country_spec.rb

describe Country, type: :model do
  describe 'FactoryBot' do
    describe '.build' do
      it 'should .save! succesfully' do
        expect { build(:country).save! }.to change { Country.count }.by(1)
      end

      it 'should not create a Country' do
        expect { build(:country) }.not_to change { Country.count }
      end

      it 'should not return a persisted instance' do
        country = build(:country)
        expect(country.id).to be_nil
        expect(country.created_at).to be_nil
        expect(country.updated_at).to be_nil
        expect(country.persisted?).to be false
      end
    end

    describe '.build_stubbed' do
      it 'should not create a Country' do
        expect { build_stubbed(:country) }.not_to change { Country.count }
      end
    end

    describe '.create' do
      it 'should create a Country' do
        expect { create(:country) }.to change { Country.count }.by(1)
      end

      it 'should return a persisted instance' do
        country = create(:country)
        expect(country.id).to be_a Integer
        expect(country.created_at).to be_a Time
        expect(country.updated_at).to be_a Time
        expect(country.persisted?).to be true
      end

      it 'should create same Country only once' do
        expect do
          3.times { create(:country) }
        end.to change { Country.count }.by(1)
      end

      it 'should return same Country on subsequent create' do
        first_country = create(:country)
        3.times do
          yet_another_country = create(:country)
          expect(yet_another_country).to eq(first_country)
        end
      end
    end
  end
end

Attempt 1

factory :country do
  initialize_with { Country.find_or_initialize_by(name: name, code: code) }
end

# Results:
# 
# Country
#   FactoryBot
#     .build
#       should .save! succesfully
#       should not create a Country
#       should not return a persisted instance
#     .build_stubbed
#       should not create a Country
#     .create
#       should create a Country
#       should return a persisted instance
#       should create same Country only once
#       should return same Country on subsequent create
# 
# Finished in 0.13141 seconds (files took 3.88 seconds to load)
# 8 examples, 0 failures

Attempt 2

factory :country do
  to_create { |instance| Country.find_or_create_by(name: instance.name, code: instance.code) }
end

# Results:
# 
#  Country
#    FactoryBot
#      .build
#        should .save! succesfully
#        should not create a Country
#        should not return a persisted instance
#      .build_stubbed
#        should not create a Country
#      .create
#        should create a Country
#        should return a persisted instance (FAILED - 1)
#        should create same Country only once
#        should return same Country on subsequent create (FAILED - 2)
#
#  Failures:
#
#    1) Country FactoryBot .create should return a persisted instance
#       Failure/Error: expect(country.id).to be_a Integer
#         expected nil to be a kind of Integer
#       # ./spec/models/country_spec.rb:38:in `block (4 levels) in <top (required)>'
#
#    2) Country FactoryBot .create should return same Country on subsequent create
#       Failure/Error: expect(yet_another_country).to eq(first_country)
#
#         expected: #<Country id: nil, name: "Malaysia", code: "MY", created_at: nil, updated_at: nil>
#              got: #<Country id: nil, name: "Malaysia", code: "MY", created_at: nil, updated_at: nil>
#
#         (compared using ==)
#
#         Diff:
#         @@ -1,4 +1,4 @@
#         -#<Country:0x00007f9fff5ac3e0
#         +#<Country:0x00007fa003485cb0
#           id: nil,
#           name: "Malaysia",
#           code: "MY",
#
#       # ./spec/models/country_spec.rb:54:in `block (5 levels) in <top (required)>'
#       # ./spec/models/country_spec.rb:52:in `times'
#       # ./spec/models/country_spec.rb:52:in `block (4 levels) in <top (required)>'
#
#  Finished in 0.13862 seconds (files took 6.39 seconds to load)
#  8 examples, 2 failures
#
#  Failed examples:
#
#  rspec ./spec/models/country_spec.rb:36 # Country FactoryBot .create should return a persisted instance
#  rspec ./spec/models/country_spec.rb:50 # Country FactoryBot .create should return same Country on subsequent create

Attempt 3.1

factory :country do
  to_create { |instance| instance.attributes = Country.find_or_create_by(name: instance.name, code: instance.code).attributes }
end

# Results:
# 
#  Country
#    FactoryBot
#      .build
#        should .save! succesfully
#        should not create a Country
#        should not return a persisted instance
#      .build_stubbed
#        should not create a Country
#      .create
#        should create a Country
#        should return a persisted instance (FAILED - 1)
#        should create same Country only once
#        should return same Country on subsequent create
#
#  Failures:
#
#    1) Country FactoryBot .create should return a persisted instance
#       Failure/Error: expect(country.persisted?).to be true
#
#         expected true
#              got false
#       # ./spec/models/country_spec.rb:41:in `block (4 levels) in <top (required)>'
#
#  Finished in 0.10734 seconds (files took 2.72 seconds to load)
#  8 examples, 1 failure
#
#  Failed examples:
#
#  rspec ./spec/models/country_spec.rb:36 # Country FactoryBot .create should return a #persisted instance

Attempt 3.2

factory :country do
  to_create do |instance|
    instance.attributes = Country.find_or_create_by(name: instance.name, code: instance.code).attributes
    instance.reload
  end
end

# Results:
# 
# Country
#   FactoryBot
#     .build
#       should .save! succesfully
#       should not create a Country
#       should not return a persisted instance
#     .build_stubbed
#       should not create a Country
#     .create
#       should create a Country
#       should return a persisted instance
#       should create same Country only once
#       should return same Country on subsequent create
# 
# Finished in 0.1177 seconds (files took 3.43 seconds to load)
# 8 examples, 0 failures

Attempt 3.3

factory :country do
  to_create do |instance|
    instance.attributes = Country.find_or_create_by(name: instance.name, code: instance.code).attributes
    instance.instance_variable_set('@new_record', false)
  end
end

# Results:
# 
# Country
#   FactoryBot
#     .build
#       should .save! succesfully
#       should not create a Country
#       should not return a persisted instance
#     .build_stubbed
#       should not create a Country
#     .create
#       should create a Country
#       should return a persisted instance
#       should create same Country only once
#       should return same Country on subsequent create
# 
# Finished in 0.07154 seconds (files took 4 seconds to load)
# 8 examples, 0 failures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.