thoughtbot / thoughtbot/factory_bot

Allow specification of default assocations depending on context

Open
#1,485 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature
Dominant language
Ruby
Stars
8.2k
Forks
2.6k
PR merge metrics
No merged PRs in 30d

Description

Problem this feature will solve

FactoryBot allows us to easily define associations that should automatically be constructed when creating or building a model. These associations are statically defined in the Factory.

If I want to change which object is used in an association I can overwrite the association when constructing an object, but I have to do that each time I want to create something. To illustrate, consider these factories:

factory :post do 
  text { 'text' }
end 

factory :comment do
  text { 'comment' }
  association :post
end

It may be fine to automatically construct a new post for every comment most of the time, but there are contexts (e.g. a small set of tests) where I always want to use a specific post. I then have to specify the association manually in each test:

def setup 
 @post = create(:post)
end

test 'first test'  do 
  create(:comment, post: post)
  create(:comment, post: post) 
  ...
end

# Imagine tons of similar tests like that below...

I would like a solution that allows greater flexibility than what is currently there.

Desired solution

TestProf provides a Factory Default helper.

It should be possible to specify a set of associations to be used in a context, e.g. a block or a test class / Rspec context, using a helper method use_factory_defaults (or similar)

The tests above could then be rewritten as:

def setup 
 @post = create(:post)
 use_factory_defaults(post: @post)
end

test 'first test'  do 
  create(:comment) # These then use @post automatically
  create(:comment) 
  ...
end

or alternatively, for a single test:

test 'first test'  do 
  use_factory_defaults(post: create(:post)) do 
    create(:comment) # These then use @post automatically
    create(:comment) 
  end
end

Alternatives considered

It is of course possible to simply use FactoryProf. However, I feel that this specific functionality would work nicely in FactoryBot itself.

As outlined above, create(:comment, post: post) is verbose when many similar models are created.

I have considered that one may be able to hack something together with traits, but I'm not even sure how. I couldn't come up with anything 😅

Additional context

TestProf provides additional helpers such as create_default, which are essentially shortcuts to the functionality outlined above.

There are parts of this feature that are strictly RSpec/Minitest specific (e.g. cleaning up defaults after a test suite is done using framework specific hooks). Including those in FactoryBot is not required.

I already have some helpers cobbled together for Minitest (since TestProf only comes with Rspec integration), and I'd be prepared to port the TestProf functionality to FactoryBot if desired 🙂

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading TestProf’s lib/test_prof/recipes/rspec/factory_default.rb, which is linked as the reference implementation. Compare its context and cleanup behavior with FactoryBot’s association handling, then define the supported use_factory_defaults API. Done means scoped defaults work for the shown create(:comment) calls without per-call overrides, with coverage for the supported usage.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
testing
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.