Skip to content

Instantly share code, notes, and snippets.

@lsaville
Last active November 8, 2016 15:10
Show Gist options
  • Save lsaville/21aed1962ea0fe620176c17c7d14772e to your computer and use it in GitHub Desktop.
Save lsaville/21aed1962ea0fe620176c17c7d14772e to your computer and use it in GitHub Desktop.

For those times when you want your tests looking good...

You might reach out to use factory girl because it's familiar. That makes sense. I felt the same way. Recently I worked to overcome that to learn a bit more about fabrication and what its all about. I'll share with you what I found.

Check out fabrication at it's slick website fabrication.org or on github. The setup is very familiar if you've dealt with factory girl, just toss the line in your gemfile and make a a sub-folder fabricators in your rails project's spec folder. From there you can create a file called fabricator.rb where the actual magic happens.

Additionally in my last project, I paired fabrication with faker, a gem that spews out random data on command with fun categories like "hipster", "starwars", and "superhero". Again it's a simple add to your project's gemfile.

In Action

In the fabricator file itself one of the fabrications I set up was that of a user,

Fabricator(:user) do
  name { Faker::Name.name }
  email { Faker::Internet.email }
  password { "pass" }
  password_confirmation { "pass" }
  role 0
end

with utilization of faker in the name and email attributes. Additionally note that this user has a default role of 0. This allowed me to call on the fabricator in my tests for a normal user:

user = Fabricate(:user)

or an admin user by overriding the default:

admin = Fabricate(:user, role: 1)

In ActiveRecord there is the distinction between calling new and create, where create makes the object and persists it to the database while new simply makes the object without persisting it. In fabrication the default mode to to create as in:

Fabricate(:user)

You still have to option of building without persistence by using:

Fabricate.build(:user)

Even More Action

To make an object with a belongs_to association, you simply call the name of the object that has_many within the belongs_to object, like this:

Fabricator(:idea) do
  name { Faker::Superhero.name }
  user
  category
end

assuming that user and category are their own fabrications.

For a more complicated situation with images associated to an idea through a joins table:

Fabricator(:idea) do
  name { Faker::Superhero.name }
  user
  category
  after_build do |idea|
    3.times { Fabricate(:ideas_image, :idea => idea, :image => Fabricate(:image)) }
  end
end

Fabricator(:ideas_image) do
end

Fabricator(:image) do
  url { Faker::Avatar.image }
end

Where the idea now has the relations of three images, a user, and a category.

Seeing is Believing

I'm always personally keen on seeing the 'thing'. The proof is in the pudding right? If you don't care skip this show section...(you might need to pump up that cmd+ to see better)

In a test set-up I have:

...
user = Fabricate(:user)
category = Fabricate(:category)
idea = Fabricate(:idea, user: user)
byebug
...

fabrications show and tell in byebug

Conclusion

I hope what little I've touched on regarding fabrication is helpful if you needed a little push to get started. Big picture, I'm not clear on whether factory girl or fabrication is superior. In my experience fabrication syntax seemed slightly more intuitive, especially regarding the creation of relations between objects.

Happy testing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment