Replace machinist with FactoryBot for test data setup#5121
Open
philippthun wants to merge 1 commit into
Open
Conversation
a98ad52 to
29d0f02
Compare
5 tasks
0d64166 to
f390170
Compare
johha
reviewed
Jun 10, 2026
| group :test do | ||
| gem 'codeclimate-test-reporter', '>= 1.0.8', require: false | ||
| gem 'machinist', '~> 1.0.6' | ||
| gem 'factory_bot', '~> 6.5' |
Contributor
There was a problem hiding this comment.
Whats the reason for pinning the version?
Member
Author
There was a problem hiding this comment.
We also pin other test gems (rspec, rubocop). Dependabot will update it accordingly.
Comment on lines
+46
to
+48
| # Sequences that mirror the original Sham.define block from | ||
| # spec/support/fakes/blueprints.rb byte-for-byte. The Sham compatibility | ||
| # shim in spec/support/sham_shim.rb delegates to these. |
Member
Author
There was a problem hiding this comment.
I kept a single line commit.
f390170 to
87aae6e
Compare
Per ADR 0015. machinist 1.0.6 has had no upstream activity since 2013
and machinist 2.0 is not a viable upgrade (no Sequel adapter, no Sham,
non-persisting make). FactoryBot is actively maintained, has trivial
Sequel integration, and provides equivalents for every pattern used
by the existing blueprints.
Convert ~11k call sites from Model.make / Model.make_unsaved to
create(:foo) / build(:foo), replace ~130 blueprints with factory
definitions under spec/support/factory_definitions/, and remove the
machinist gem along with spec/support/fakes/blueprints.rb and
spec/support/machinist_monkey_patch.rb.
Key technical decisions (see ADR 0015):
- Global to_create { |i| i.save; i.refresh } in
spec/support/factories.rb. This matches machinist's Sequel adapter
which both saved and refreshed; the refresh prevents stale-cache
bugs whenever a factory's after-create hook mutates associations.
- Sham is preserved as a thin shim (spec/support/sham_shim.rb) that
delegates Sham.<name> to FactoryBot.generate(:sham_<name>) sequences
defined in spec/support/factories.rb. The shim mirrors the original
Sham.define block 1:1 so existing call sites need no edits.
- Dynamic class -> factory-name conversion via
klass.name.demodulize.underscore.to_sym is used in matchers and
shared examples, so generic helpers continue to look up the right
factory when given any model class.
- Named blueprints become traits: Foo.blueprint(:bar) turns into a
trait :bar on the :foo factory; Foo.make(:bar, x: 1) becomes
create(:foo, :bar, x: 1).
- build replaces make_unsaved for the (rare) cases that wanted an
unsaved instance.
- :droplet_model only auto-sets itself as the app's current droplet
when no app: override is supplied (set_as_current_droplet
{ app == :unset }), matching machinist's blueprint where the default
app block only ran in that case. Specs that previously relied on the
auto-set side effect when passing app: explicitly call
app.update(droplet:) just as the pre-migration versions did.
- :revision_sidecar_process_type_model builds its parent with the
:no_process_types trait so FactoryBot.lint does not collide with the
parent's after-create web row on the (revision_sidecar_guid, type)
unique constraint.
87aae6e to
da85ce8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Per ADR 0015. machinist 1.0.6 has had no upstream activity since 2013 and machinist 2.0 is not a viable upgrade (no Sequel adapter, no Sham, non-persisting make). FactoryBot is actively maintained, has trivial Sequel integration, and provides equivalents for every pattern used by the existing blueprints.
Convert ~11k call sites from
Model.make/Model.make_unsavedtocreate(:foo)/build(:foo), replace ~130 blueprints with factory definitions under spec/support/factory_definitions/, and remove the machinist gem along with spec/support/fakes/blueprints.rb and spec/support/machinist_monkey_patch.rb.Key technical decisions (see ADR 0015):
to_create { |i| i.save; i.refresh }in spec/support/factories.rb. This matches machinist's Sequel adapter which both saved and refreshed; the refresh prevents stale-cache bugs whenever a factory's after-create hook mutates associations.Sham.<name>toFactoryBot.generate(:sham_<name>)sequences defined in spec/support/factories.rb. The shim mirrors the originalSham.defineblock 1:1 so existing call sites need no edits.klass.name.demodulize.underscore.to_symis used in matchers and shared examples, so generic helpers continue to look up the right factory when given any model class.Foo.blueprint(:bar)turns into a trait:baron the:foofactory;Foo.make(:bar, x: 1)becomescreate(:foo, :bar, x: 1).make_unsavedfor the (rare) cases that wanted an unsaved instance.:droplet_modelonly auto-sets itself as the app's current droplet when noapp:override is supplied (set_as_current_droplet { app == :unset }), matching machinist's blueprint where the default app block only ran in that case. Specs that previously relied on the auto-set side effect when passingapp:explicitly callapp.update(droplet:)just as the pre-migration versions did.:revision_sidecar_process_type_modelbuilds its parent with the:no_process_typestrait soFactoryBot.lintdoes not collide with the parent's after-create web row on the(revision_sidecar_guid, type)unique constraint.I have reviewed the contributing guide
I have viewed, signed, and submitted the Contributor License Agreement
I have made this pull request to the
mainbranchI have run all the unit tests using
bundle exec rakeI have run CF Acceptance Tests