factory girl
Post on 05-Dec-2014
7.214 Views
Preview:
DESCRIPTION
TRANSCRIPT
Factory GirlA Brief Introduction Using Ruby on Rails
Factory GirlA Brief Introduction Using Ruby on Rails
Yet Another Blog Example
What’s Factory Girl?
A Replacement for Fixtures
Provides a Simple DSL
Keeps TestsFocused & Readable
Builds Objects Instead of Database Records
Installation
Gemfile
group :development, :test do gem ‘factory_girl_rails’end
Gemfile
$ bundle install
Defining a Factory
spec/factories/
spec/factories/users.rb
spec/factories/posts.rb
spec/factories/comments.rb
spec/factories/products.rb
spec/factories/users.rb
FactoryGirl.define do factory :user do name ‘Joe Blow’ email ‘joe.blow@example.com’ password ‘p@ssw0rd’ admin false endend
spec/factories/users.rb
spec/models/user_spec.rb
spec/models/user_spec.rb
describe User do
end
spec/models/user_spec.rb
describe User do subject { FactoryGirl.create(:user) }
end
spec/models/user_spec.rb
describe User do subject { FactoryGirl.create(:user) }
its(:name) { should == ‘Joe Blow’ }
end
spec/models/user_spec.rb
describe User do subject { FactoryGirl.create(:user) }
its(:name) { should == ‘Joe Blow’ } its(:email) { should == ‘joe.blow@example.com’ }
end
describe User do subject { FactoryGirl.create(:user) }
its(:name) { should == ‘Joe Blow’ } its(:email) { should == ‘joe.blow@example.com’ }
it { should_not be_admin }end
spec/models/user_spec.rb
FactoryGirl.create(:user)
FactoryGirl.build(:user)
FactoryGirl.build_stubbed(:user)
spec/spec_helper.rb
RSpec.configure do |config| config.include FactoryGirl::Syntax::Methodsend
spec/spec_helper.rb
FactoryGirl.create(:user)
create(:user)
build(:user)
build_stubbed(:user)
spec/models/user_spec.rb
describe User do subject { create(:user) }
its(:name) { should == ‘Joe Blow’ } its(:email) { should == ‘joe.blow@example.com’ }
it { should_not be_admin }end
Overriding Attributes
Keep Only Relevant Attributes in Tests
spec/models/user_spec.rb
context ‘a duplicate email address’ do it { should_not be_valid }end
context ‘a duplicate email address’ do let(:first_user) { User.create(name: ‘Joe First’, email: ‘joe@example.com’, password: ‘test123’, admin: false) } subject { User.new(name: ‘Joe Duplicate’, email: first_user.email, password: ‘test123’, admin: false) }
it { should_not be_valid }end
spec/models/user_spec.rb
context ‘a duplicate email address’ do let(:user) { create(:user) } subject { build(:user, email: user.email) }
it { should_not be_valid }end
spec/models/user_spec.rb
Lazy Attributes
Lazy Attributes Are Dynamic Attributes
spec/factories/posts.rb
FactoryGirl.define do factory :post do title ‘This is my post.’ content ‘There are many like it, but this one is mine.’ published_at Time.now endend
irb(main):001:0> FactoryGirl.create(:post)
irb(main):001:0> FactoryGirl.create(:post)=> #<Post id: 1, title: “This is my post.”, content: “There are many like it, but this one is mine.”, published_at: 2012-12-20 23:47:34 UTC>
group :development, :test do gem ‘factory_girl_rails’ gem ‘ffaker’end
Gemfile
spec/factories/posts.rb
FactoryGirl.define do factory :post do title { Faker::Lorem.sentence } content { Faker::Lorem.sentences.join(‘ ’) } published_at { Time.now } endend
irb(main):001:0> FactoryGirl.create(:post)
irb(main):001:0> FactoryGirl.create(:post)=> #<Post id: 2, title: “Lorem ipsum dolor sit amet, consectetur adipiscing elit.”, content: “Pellentesque adipiscing varius suscipit …”, published_at: 2012-12-20 23:48:14 UTC>
irb(main):001:0> FactoryGirl.create(:post)=> #<Post id: 3, title: “Nulla id augue ut mauris pharetra tincidunt ac sed velit.”, content: “Nullam tincidunt, dolor quis pellentesque …”, published_at: 2012-12-20 23:49:06 UTC>
Sequences
Reuse Common Attributes
FactoryGirl.define do sequence :email do |n| “person#{n}@example.com” endend
spec/factories/sequences.rb
FactoryGirl.define do factory :user do name { Faker::Name.name } email password ‘p@ssw0rd’ admin false endend
spec/factories/users.rb
person1@example.com
person1@example.com,person2@example.com
person1@example.com,person2@example.com,person3@example.com
person1@example.com,person2@example.com,person3@example.com,etc.
Dependent Attributes
Attributes FromOther Attributes
spec/factories/users.rb
FactoryGirl.define do factory :user do name ‘Joe Blow’ email ‘joe.blow@example.com’ password ‘p@ssw0rd’ admin false endend
spec/factories/users.rb
FactoryGirl.define do factory :user do name ‘Joe Blow’ email { ‘#{name.gsub(/\s/, ‘.’)}@example.com’.downcase } password ‘p@ssw0rd’ admin false endend
irb(main):001:0> FactoryGirl.create(:user)=> #<User id: 1, name: “Joe Blow”, email: “joe.blow@example.com”, password: “p@ssw0rd”, admin: false>
irb(main):001:0> FactoryGirl.create(:user, name: ‘Joe Mama’)=> #<User id: 2, name: “Joe Mama”, email: “joe.mama@example.com”, password: “p@ssw0rd”, admin: false>
Traits
Specify Types Of Factories
describe Post do context ‘an unpublished post’ do subject { create(:post, published_at: nil) }
it ‘will never be read’ do # ... end endend
FactoryGirl.define do factory :post do title { Faker::Lorem.sentence } content { Faker::Lorem.sentences.join(‘ ’) } published_at { Time.now } endend
spec/factories/posts.rb
FactoryGirl.define do factory :post do title { Faker::Lorem.sentence } content { Faker::Lorem.sentences.join(‘ ’) } published_at { Time.now } trait :unpublished do published_at nil end endend
spec/factories/posts.rb
describe Post do context ‘an unpublished post’ do subject { create(:post, :unpublished) }
it ‘will never be read’ do # ... end endend
spec/models/post_spec.rb
Associations
Build Associated Objects From Factories
class Post < ActiveRecord::Base belongs_to :userend
app/models/post.rb
irb(main):001:0> FactoryGirl.create(:post)=> #<Post id: …, title: “…”, content: “…”, published_at: …, user: nil>
FactoryGirl.define do factory :post do title { Faker::Lorem.sentence } content { Faker::Lorem.sentences.join(‘ ’) } published_at { Time.now } trait :unpublished do published_at nil end endend
spec/factories/posts.rb
FactoryGirl.define do factory :post do user title { Faker::Lorem.sentence } content { Faker::Lorem.sentences.join(‘ ’) } published_at { Time.now } trait :unpublished do published_at nil end endend
spec/factories/posts.rb
irb(main):001:0> FactoryGirl.create(:post)=> #<Post …, user: #<User id: 123, name: “John Wayne”, …>>
Transient Attributes
Customize Behavior With Fake Attributes
FactoryGirl.define do factory :post do ignore do unapproved false end
title { unapproved ? “ಠ_ಠ” : “This is my post.” } endend
spec/factories/posts.rb
FactoryGirl.define do factory :post do ignore do unapproved false end
title { unapproved ? “ಠ_ಠ” : “This is my post.” } endend
spec/factories/posts.rb
FactoryGirl.define do factory :post do ignore do unapproved false end
title { unapproved ? “ಠ_ಠ” : “This is my post.” } endend
spec/factories/posts.rb
irb(main):001:0> FactoryGirl.create(:post)=> #<Post id: 2, title: “This is my post.”>
irb(main):001:0> FactoryGirl.create(:post, unapproved: true)=> #<Post id: 2, title: “ಠ_ಠ”>
Creating or Building Multiple Objects
Build a Shitload Of Objects
FactoryGirl.create_list(:model, 5)
FactoryGirl.build_list(:model, 5)
FactoryGirl.build_stubbed_list(:model, 5)
irb(main):001:0> FactoryGirl.create_list(:post, 5)
irb(main):001:0> FactoryGirl.create_list(:post, 5)=> [#<Post id: 1, title: “This is my post.”>, #<Post id: 2, title: “This is my post.”>, #<Post id: 3, title: “This is my post.”>, #<Post id: 4, title: “This is my post.”>, #<Post id: 5, title: “This is my post.”>]
Callbacks
Execute Arbitrary Code When Building & Creating
class User < ActiveRecord::Base has_many :postsend
app/models/user.rb
FactoryGirl.define do factory :user_with_posts do ignore do posts_count 5 end
after(:create) do |user, evaluator| FactoryGirl.create_list(:post, evaluator.posts_count, user: user) end endend
spec/factories/users.rb
irb(main):001:0> FactoryGirl.create(:user).posts.length=> 0
irb(main):001:0> FactoryGirl.create(:user_with_posts).posts.length=> 5
irb(main):001:0> FactoryGirl.create(:user_with_posts,posts_count: 15).posts.length=> 15
Wrapping Up...
Factory Girl is Magic
Easier to Maintain
Less of a Headache
Fun to Work With
Questions?
top related