Here we demonstrate:
- string sequences
- many-to-one association
- skipping acl validations
- simple convenience trait
FactoryGirl.define do
factory :project do
sequence :name, 'a'
sequence :long_name, 'a'
user
skip_acl_validations true
trait :core do
core true
end
end
endTest this with rails console test
include FactoryGirl::Syntax::Methods
create(:project)
Project.first.attributes == {
"id"=>269,
"name"=>"a",
"long_name"=>"a",
"description"=>nil,
"internal"=>true,
"active"=>true,
"created_at"=>Tue, 03 Sep 2013 20:16:38 UTC +00:00,
"updated_at"=>Tue, 03 Sep 2013 20:16:38 UTC +00:00,
"image_url"=>nil,
"private"=>false,
"force_output_rtl"=>false,
"core"=>false,
"export_config"=>nil,
"user_id"=>2529
}
# Remember to cleanup your test database
Project.destroy_all
User.destroy_all # Automatically created from Project creation
Locale.destroy_all # Automatically created from User creationHere we demonstrate:
- sequence of digits as a string
- factory parameter, not saved as an attribute, using the ignore block
- many-to-many association using after(:create)
- attribute's value taken from block
- Bonus Points: Is something missing? Can you tell me what should also be here?
FactoryGirl.define do
factory :user do
sequence :login, 'a'
sequence :twitter_id, '1'
# There's no validation requiring users to have locales
# however it's often assumed, so we'll require it here
ignore do # Ignored attributes aren't set on the model
locale { create :locale }
end
after(:create) do |user, ignored_attributes|
locale = ignored_attributes.locale
create(:translator_locale, user: user, locale: locale.code)
end
trait :blocked do
blocked true
end
trait :moderator do
after(:create) { |u| u.groups << Group.moderator }
end
trait :admin do
after(:create) { |u| u.groups << Group.admin }
end
trait :engineer do
after(:create) { |u| u.groups << Group.engineer }
end
end
endHere we demonstrate:
- complex convenience trait to build a typical production instance
- use factory to create multiple instances at once
- many-to-many association populated with a list
FactoryGirl.define do
factory :priority_task do
trait :with_basic_attributes do
user
sequence :description, 'a'
sequence :jira_ticket, 'a'
sequence :url, 'a'
user_action_type
locales { create_list :locale, 5 }
end
trait :active do
active true
end
end
endFind two things wrong with this factory.
FactoryGirl.define do
factory :locale do
sequence :code, 'a'
sequence :english_name, 'a'
sequence :local_name, 'a'
trait :rtl do
rtl true
end
trait :homepage do
show_on_homepage true
end
factory :locale_on_homepage, traits: [:homepage]
factory :locale_with_hashtag_widget do
hashtag { hashtag_from_code }
sequence :widget_id
end
end
endDescribe what this does? How does it work? What is added to the database?
locale = create(:locale, :rtl, english_name: 'esperanto')
user = create(:user, locale: locale)
create(:project, :core, long_name: 'esperanto', user: user)
create_list(:priority_task, 35, :active)Don't want to save to the database right away? Build the attributes instead; maybe a controller wants to show off its saving skills!
project_attributes = build_attributes(:project, :core)
Project.create!(project_attributes)Note: In a repl make sure to also require './spec/spec_helper.rb' to include the build_attributes method.
What is going on here? Why don't we call Factory Girl's attributes_for method directly?
# Steal attributes off of factory girl's build()
# because attributes_for() doesn't include attributes for associations
# Source: http://stackoverflow.com/questions/10290286/factorygirl-why-does-attributes-for-omit-some-attributes
# Issue: https://github.com/thoughtbot/factory_girl/issues/316
#
# This is also an easy place to ditch the acl flag, which isn't an attribute
def build_attributes(*args)
FactoryGirl.build(*args).attributes.delete_if do |k, v|
v.nil? || k == 'skip_acl_validations'
end
end"only provide attributes that are required through validations and that do not have defaults" -- docs
Traits add convenient optional properties, extending the base factory. Avoid using nested factories in favor of traits, which are composable and self-documenting.
Provide sequences in-line, even if using a block.
What is the default sequence, with no params? i.e. sequence :my_attribute
When would be want a sequence with a block? i.e. sequence :my_attribute { |i| ... }
What would the factory for country.rb look like?
Provide a :production trait for every factory so we can generate production-like data for local development, staging, and maybe smoke tests. This would replace dumping production mysql data into our local instances, and replace any plans of using static seed data.