Generating Test Data With FactoryGirl
While testing Rails applications, you often need sample data to try out features in your app. The general flow is to create some data, perform operations on them, then make assertions about the data or expect some changes in your application.
Rails does this with Fixtures which can be used to stub-out sample data. But it becomes tedious when there is a need for multiple data that vary slightly, to build model associations or to create models with unique values. This is where FactoryGirl shines.
Factory Girl provides a nice way to define and create dynamic data using some predefined set of values.
Getting Started
We will be modeling a music domain. To get started let's define a factory to create data for a song model.
Defining factories
FactoryGirl.define do
factory :song do
title "One Dance"
artist "Drake"
genre "Hip-Hop"
year 2016
end
end
Use factory to create data
song = FactoryGirl.create(:song)
# Change default title attribute.
controlla = FactoryGirl.create(:song, title: "Controlla")
# Create collection of songs
songs = FactoryGirl.create_list(:songs, 10)
<small>
Pro tip: if you just need a song instance and don't need the song to be saved to your test database, use FactoryGirl.build(:song)
instead.
</small>
Building Associations
FactoryGirl also allows you to define model associations pretty easily. To demonstrate this we'll make the artist attribute of our Song factory a factory on it's own, as opposed to just being a string.
FactoryGirl.define do
# Artist Factory
factory :artist do
name "Drake"
label "OVO Sound"
end
# Song Factory
factory :song do
title "One Dance"
artist factory: :artist
genre "Hip-Hop"
year 2016
end
end
# Usage
song = FactoryGirl.create(:song)
song.artist.name #=> "Drake"
Sequence
Sequence is another cool feature of FactoryGirl, that makes it easy to create multiple data with unique values. This is useful when your data model has an attribute that should be unique, like emails, ID numbers etc. We will introduce a track number attribute to our Song factory to show this.
# Song Factory
FactoryGirl.define do
factory :song do
title "One Dance"
artist factory: :artist
genre "Hip-Hop"
sequence(:track_number) {|n| n } # n += 1 for each new instance.
year 2016
end
end
FactoryGirl.create(:song).track_number #=> 1
FactoryGirl.create(:song).track_number #=> 2
# For emails we might have something like
sequence(:email) { |n| "someone#{n}@mail.com" }
Traits
FactoryGirl uses "Traits" to give additional attributes to objects.
We can modify our song factory to only assign album and track numbers to songs that are part of an album. That is songs that are not singles.
# Song Factory
FactoryGirl.define do
factory :song do
title "One Dance"
artist factory: :artist
genre "Hip-Hop"
year 2016
trait :has_album do
album "Views"
sequence(:track_number) {|n| n }
end
end
end
FactoryGirl.create(:song).track_number #=> nil
# use :has_album trait
FactoryGirl.create(:song, :has_album).track_number #=> 1
Attributes
Finally, there are times when you just need a hash of attributes for a model, which you can use to test POST controller actions. FactoryGirl provides attributes_for
.
song_params = FactoryGirl.attributes_for(:song)
#=> { title: "One Dance", genre: "Hip-Hop", year: 2016 }
song_params = FactoryGirl.attributes_for(:song, :has_album)
#=> { title: "One Dance", genre: "Hip-Hop", year: 2016, album: "Views", track_number: 1 }
Conclusion
FactoryGirl provides a really simple DSL to generate dynamic data for our test. It offers a lot more and this simple introduction should get you started. Check out the official guide to read more.