Skip to content

Instantly share code, notes, and snippets.

@suchov
Created April 12, 2017 19:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save suchov/83502cacf6641b2077f923306a97338f to your computer and use it in GitHub Desktop.
Save suchov/83502cacf6641b2077f923306a97338f to your computer and use it in GitHub Desktop.
Using Factories Like Fixtures
While we prefer factories over fixtures, it is important to use factories appropriately
to get any benefit. Occasionally we’ll see test suites create factory definitions as if they were fixtures:
factory :pam, class: User do
name "Pam"
manager false
end
factory :michael, class: User do
name "Michael"
manager true
end
This is the worst of both worlds. Factories are great because they’re flexible, however they are slower than fixtures.
When you use them like fixtures, they are slow, inflexible, and cryptic. As the factory definitions grow, they tend to
violate the rule of having a minimal set of attributes for a valid records. In addition to the issues that brings, it
becomes difficult to remember which factories return which attributes.
Instead of creating multiple factory definitions to group related functionality, use traits or nested factories.
Traits allow you to compose attributes within the test itself.
factory :message do
body "What's up?"
trait :read do
read_at { 1.month.ago }
end
end
# In the test
build_stubbed(:message, :read) # it's clear what we're getting here
You may even consider pulling traits out to the global level for reuse between fac- tories:
factory :message do
#noop
end
factory :notification do
#noop
end
trait :read do
read_at { 1.month.ago }
end
# In the test
build_stubbed(:message, :read)
build_stubbed(:notification, :read)
In addition to traits, you can extend functionality through inheritance with nested factories:
factory :user do
sequence(:username) { |n| "username#{n}" }
password_digest "password"
factory :subscriber do
subscribed true
end
end
# In the test
build_stubbed(:subscriber)
This allows you to better communicate state and still maintain a single source of
knowledge about the necessary attributes to build a user.
# This is good
build_stubbed(:user, :subscribed)
# This is better
build_stubbed(:subscriber)
Note that nesting is not as composable as traits since you can only build an object
from a single factory. Traits, however, are more flexible as multiple can be used at the same time.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment