Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add find_or_create_by Method #1681

Open
hatsu38 opened this issue Jul 20, 2024 · 1 comment
Open

Add find_or_create_by Method #1681

hatsu38 opened this issue Jul 20, 2024 · 1 comment
Labels

Comments

@hatsu38
Copy link

hatsu38 commented Jul 20, 2024

Problem this feature will solve

When setting up test data with FactoryBot, it can be cumbersome and repetitive to check if a record exists before creating it.
For instance, in our current test setup, we have to manually use find_by followed by create if the record is not found.

RSpec.describe User do 
  before(:all) { Fixtures.setup_basics }
  
  it do
    # aa
  end
  
  it do
    # aa
  end
end


module Fixtures
  def self.setup_basics
    setup_normal_plan
    setup_high_plan
  end

  def self.normal_plan
      a_token = FactoryBot.create(:token :free)
      b_token = FactoryBot.create(:token, :normal)
     # etc...
  end

  def self.high_plan
    a_token = Token.find_by(name: "free") || FactoryBot.create(:token :free)
    b_token = Token.find_by(name: "normal") || FactoryBot.create(:token :normal)
  end
end

Desired solution

  def self.high_plan
    a_token = Token.find_or_create_by(:token :free)
    b_token = Token.find_or_create_by(:token :normal)
  end

Alternatives considered

  def self.high_plan
    a_token = Token.find_by(name: "free") || FactoryBot.create(:token :free)
    b_token = Token.find_by(name: "normal") || FactoryBot.create(:token :normal)
  end

Additional context

@colinross
Copy link
Contributor

I believe that is somewhat intended. Sharing data between test runs is usually a code smell, either in the runtime code or your testing code.

Assuming you have some level of cleanup strategy, why not just create a new token each time? is the name a hardcoded value in your runtime code? if the object is highly complex and/or for instance, provided by an external service, have you thought of using mocks?

I get what you are asking for here, but passive (ab)use of a Find_or_create (in a test suite for actor objects) often leads to flaky test suites.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants