SlideShare a Scribd company logo
1 of 26
Philly.rb meetup
Rails testing:
factories or
fixtures?
factories or
Michael Toppa
March 11, 2014
@mtoppa
Why use factories or fixtures?
❖ Factories and fixtures can simplify otherwise repetitive and
complex data setup for tests
❖ Your need for them in unit tests will be light if you do TDD
with loosely-coupled code
❖ But they are vital for unit-“ish” testing if you’re working with
tightly coupled code
❖ e.g. most Rails apps, and the examples in this presentation
❖ They are great for integration testing
Comparisons
❖ Tests with no factories or fixtures
❖ Tests with fixtures
❖ Tests with factories, using FactoryGirl
❖ We’ll test the same method in each case, so you can
clearly see the differences
Partial data model for our
examples
CandidateCandidate
(politician)(politician)
RaceRaceCampaignCampaign
OfficeOffice
CurrentCurrent
HoldersHolders
Winning Campaign
Our test case
Tests with no factories or
fixtures
Ok for simple cases
# spec/models/candidate_spec.rb
describe Candidate do
describe "#calculate_completeness" do
it "returns 0 when no fields are filled out" do
toppa = Candidate.new
toppa.calculate_completeness.should eq(0.0)
end
it "returns a ratio of filled-out fields to total fields" do
toppa = Candidate.new
toppa.name = "Mike Toppa"
toppa.facebook_url = "https://facebook/ElJefe"
toppa.wikipedia_url = "http://en.wikipedia.org/wiki/Mike_Toppa"
toppa.calculate_completeness.should eq(0.2) # 3 / 15 = 0.2
end
end
Not so good for complex
cases# spec/models/race_spec.rb
describe Race do
describe '#inaugurate!' do
it 'makes Mike Toppa President of the United States' do
toppa = Candidate.create(
name: 'Mike Toppa',
[and all required attributes]
)
president = Office.create(
title: 'President of the United States',
[and all required attributes]
)
presidential_race = Race.create([president + all req attrs])
toppa_campaign = Campaign.create([toppa + presidential_race + all
req attrs])
presidential_race.winning_campaign = toppa_campaign
presidential_race.inaugurate!
president.current_holders.first.should == toppa
end
end
end
Tests with fixtures
The fixture files
# spec/fixtures/candidates.yml
mike_toppa:
id: 1
name: Mike Toppa
gender: M
[etc…]
# spec/fixtures/office.yml
president:
id: 1
title: President of the United States
level: N
[etc…]
# spec/fixtures/race.yml
president_race_2012:
id: 1
office: president
election_day: 10/4/2012
[etc…]
# spec/fixtures/campaign.yml
toppa_us_president_campaign_2012:
id: 1
race: president_race_2012
candidate: mike_toppa
fec_id: XYZ
The test file
# spec/models/race_spec.rb
describe Race do
describe '#inaugurate!' do
it 'makes Mike Toppa President of the United States' do
toppa = candidates(:mike_toppa)
president = offices(:president)
presidential_race = races(:us_president_race_2012)
toppa_campaign = campaigns(:toppa_us_president_campaign_2012)
presidential_race.winning_campaign = toppa_campaign
presidential_race.inaugurate!
president.current_holders.first.should == toppa
end
end
end
Pros
❖ For simple scenarios, re-usable across tests
❖ Easy to generate from live data
❖ Fixture files are easy to read
❖ Tests are fairly fast
❖ Records are inserted based on the fixture files,
bypassing ActiveRecord
Cons
❖ Brittle
❖ If you add required fields to a model, you have to update
all its fixtures
❖ Fixture files are an external dependency
❖ Fixtures are organized by model - you need to keep track
of their relationships with test scenarios
❖ Not dynamic - you get the same values every time
❖ (this may or may not be ok)
Tests with factories,
using FactoryGirl
using FactoryGirl
The factory files
# spec/factories/candidates.rb
FactoryGirl.define do
factory :candidate do
name 'Jane Doe'
gender 'F'
[etc…]
# spec/factories/offices.rb
FactoryGirl.define do
factory :office do
title 'Senator'
level 'N'
[etc…]
# spec/factories/races.rb
FactoryGirl.define do
factory :race do
office
election_day '11/04/2014'.to_datetime
[etc…]
# spec/factories/campaigns.rb
FactoryGirl.define do
factory :campaign do
candidate
race
fec_id 'XYZ'
The test file
# spec/models/race_spec.rb
describe Race do
describe '#inaugurate!' do
it 'makes Mike Toppa President of the United States' do
toppa = create :candidate, name: 'Mike Toppa'
president = create(
:office,
title: 'President of the United States'
)
presidential_race = create :race, office: president
toppa_campaign = create(
:campaign,
candidate: toppa,
race: presidential_race
)
presidential_race.winning_campaign = toppa_campaign
presidential_race.inaugurate!
president.current_holders.first.should == toppa
end
end
end
But wait, there’s more…
Randomized values with the
Faker gem
# spec/factories/candidates.rb
FactoryGirl.define do
factory :candidate do
name { Faker::Name.name }
wikipedia_url { Faker::Internet.url }
short_bio { Faker::Lorem.paragraph }
phone { Faker::PhoneNumber.phone_number}
address_1 { Faker::Address.street_address }
address_2 { Faker::Address.secondary_address }
city { Faker::Address.city }
state { Faker::Address.state }
zip { Faker::Address.zip_code }
# and other kinds of randomized values
gender { |n| %w[M F].sample }
sequence(:pvs_id)
azavea_updated_at { Time.at(rand * Time.now.to_i) }
[etc…]
Debate on randomized values
❖ Argument for:
❖ Having a wide variety of values, and combinations of values,
in your tests can expose bugs you might otherwise miss
❖ Argument against:
❖ In a test using many different model instances, failures can be
difficult to reproduce and debug
❖ If you’re counting on randomized values to find bugs, your
design process may not be robust
Instantiation options
❖ create: saves your object to the database, and saves
any associated objects to the database
❖ build: builds your object in memory only, but still
saves any associated objects to the database
❖ build_stubbed: builds your object in memory only, as
well as any associated objects
Instantiation options
❖ Use build_stubbed whenever possible - your tests
will be faster!
❖ You will need to use create or build for integration
testing
❖ …and if you’re stuck with tightly coupled Rails code
For frequent scenarios: child
factories
# spec/factories/offices.rb
FactoryGirl.define do
factory :office do
title 'Mayor'
level 'L'
[etc…]
factory :office_president do
status 'A'
title 'President of the United States'
level 'N'
[etc…]
end
end
end
# spec/models/race_spec.rb
describe Race do
describe '#inaugurate!' do
it 'makes Mike Toppa President of the United States' do
president = create :office_president
[etc…]
end
end
end
Child factories using other child
factories
# spec/factories/offices.rb
FactoryGirl.define do
factory :office do
area
title 'Mayor'
level 'L'
[etc…]
factory :office_house do
association :area, factory: :congressional_district
status 'A'
level 'N'
type_code 'H'
[etc…]
end
end
end
For frequent scenarios: traits
# spec/factories/candidates.rb
FactoryGirl.define do
factory :candidate do
name 'Jane Doe'
gender 'F'
[etc…]
end
trait :with_office_house do
after :create do |candidate|
office = create :office_house
create :current_office_holder, :office => office, :candidate => candidate
end
end
end
# spec/models/race_spec.rb
describe Race do
describe '#inaugurate!' do
it 'makes Mike Toppa President of the United States' do
toppa = create: candidate, :with_office_house
[etc…]
end
end
end
Don’t overuse child factories
and traits - leads to brittleness
Factories address shortcomings of
fixtures
❖ Not as brittle
❖ Factory won’t break if you add a new required field to a model
❖ You don’t need to maintain complex scenarios spread out across
fixture files
❖ Lessened external dependency, more flexibility
❖ You can define the attributes important to the test in the test code
itself
❖ When using build_stubbed your tests will be faster
❖ But fixtures are faster when inserting records

More Related Content

Similar to Rails testing: factories or fixtures?

fixtures_vs_AR_vs_factories.ppt
fixtures_vs_AR_vs_factories.pptfixtures_vs_AR_vs_factories.ppt
fixtures_vs_AR_vs_factories.pptTom Plisskin
 
Oracle APEX for Beginners
Oracle APEX for BeginnersOracle APEX for Beginners
Oracle APEX for BeginnersDimitri Gielis
 
Unit Test in Ruby on Rails by Minitest
Unit Test in Ruby on Rails by MinitestUnit Test in Ruby on Rails by Minitest
Unit Test in Ruby on Rails by MinitestHosang Jeon
 
Six simple steps to unit testing happiness
Six simple steps to unit testing happinessSix simple steps to unit testing happiness
Six simple steps to unit testing happinessSteven Feuerstein
 
Writing useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you buildWriting useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you buildAndrei Sebastian Cîmpean
 
[DSC Europe 22] Engineers guide for shepherding models in to production - Mar...
[DSC Europe 22] Engineers guide for shepherding models in to production - Mar...[DSC Europe 22] Engineers guide for shepherding models in to production - Mar...
[DSC Europe 22] Engineers guide for shepherding models in to production - Mar...DataScienceConferenc1
 
WEBINAR: Proven Patterns for Loading Test Data for Managed Package Testing
WEBINAR: Proven Patterns for Loading Test Data for Managed Package TestingWEBINAR: Proven Patterns for Loading Test Data for Managed Package Testing
WEBINAR: Proven Patterns for Loading Test Data for Managed Package TestingCodeScience
 
Continuous Load Testing with CloudTest and Jenkins
Continuous Load Testing with CloudTest and JenkinsContinuous Load Testing with CloudTest and Jenkins
Continuous Load Testing with CloudTest and JenkinsSOASTA
 
Developer Tests - Things to Know
Developer Tests - Things to KnowDeveloper Tests - Things to Know
Developer Tests - Things to KnowVaidas Pilkauskas
 
10 Tips for Configuring Your Builds with Bamboo Specs
10 Tips for Configuring Your Builds with Bamboo Specs10 Tips for Configuring Your Builds with Bamboo Specs
10 Tips for Configuring Your Builds with Bamboo SpecsAtlassian
 
Continuous Load Testing with CloudTest and Jenkins
Continuous Load Testing with CloudTest and JenkinsContinuous Load Testing with CloudTest and Jenkins
Continuous Load Testing with CloudTest and JenkinsSOASTA
 
Test automation Frame Works
Test automation Frame WorksTest automation Frame Works
Test automation Frame WorksvodQA
 
An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development CodeOps Technologies LLP
 
CoreData - there is an ORM you can like!
CoreData - there is an ORM you can like!CoreData - there is an ORM you can like!
CoreData - there is an ORM you can like!Tomáš Jukin
 
Implement BDD with Cucumber and SpecFlow
Implement BDD with Cucumber and SpecFlowImplement BDD with Cucumber and SpecFlow
Implement BDD with Cucumber and SpecFlowTechWell
 
Agile Data Science on Greenplum Using Airflow - Greenplum Summit 2019
Agile Data Science on Greenplum Using Airflow - Greenplum Summit 2019Agile Data Science on Greenplum Using Airflow - Greenplum Summit 2019
Agile Data Science on Greenplum Using Airflow - Greenplum Summit 2019VMware Tanzu
 
Getting your mobile test automation process in place - using Cucumber and Cal...
Getting your mobile test automation process in place - using Cucumber and Cal...Getting your mobile test automation process in place - using Cucumber and Cal...
Getting your mobile test automation process in place - using Cucumber and Cal...Niels Frydenholm
 
Scaling Ride-Hailing with Machine Learning on MLflow
Scaling Ride-Hailing with Machine Learning on MLflowScaling Ride-Hailing with Machine Learning on MLflow
Scaling Ride-Hailing with Machine Learning on MLflowDatabricks
 

Similar to Rails testing: factories or fixtures? (20)

fixtures_vs_AR_vs_factories.ppt
fixtures_vs_AR_vs_factories.pptfixtures_vs_AR_vs_factories.ppt
fixtures_vs_AR_vs_factories.ppt
 
Testing smells
Testing smellsTesting smells
Testing smells
 
Oracle APEX for Beginners
Oracle APEX for BeginnersOracle APEX for Beginners
Oracle APEX for Beginners
 
Unit Test in Ruby on Rails by Minitest
Unit Test in Ruby on Rails by MinitestUnit Test in Ruby on Rails by Minitest
Unit Test in Ruby on Rails by Minitest
 
Six simple steps to unit testing happiness
Six simple steps to unit testing happinessSix simple steps to unit testing happiness
Six simple steps to unit testing happiness
 
Writing useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you buildWriting useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you build
 
[DSC Europe 22] Engineers guide for shepherding models in to production - Mar...
[DSC Europe 22] Engineers guide for shepherding models in to production - Mar...[DSC Europe 22] Engineers guide for shepherding models in to production - Mar...
[DSC Europe 22] Engineers guide for shepherding models in to production - Mar...
 
WEBINAR: Proven Patterns for Loading Test Data for Managed Package Testing
WEBINAR: Proven Patterns for Loading Test Data for Managed Package TestingWEBINAR: Proven Patterns for Loading Test Data for Managed Package Testing
WEBINAR: Proven Patterns for Loading Test Data for Managed Package Testing
 
Continuous Load Testing with CloudTest and Jenkins
Continuous Load Testing with CloudTest and JenkinsContinuous Load Testing with CloudTest and Jenkins
Continuous Load Testing with CloudTest and Jenkins
 
Developer Tests - Things to Know
Developer Tests - Things to KnowDeveloper Tests - Things to Know
Developer Tests - Things to Know
 
10 Tips for Configuring Your Builds with Bamboo Specs
10 Tips for Configuring Your Builds with Bamboo Specs10 Tips for Configuring Your Builds with Bamboo Specs
10 Tips for Configuring Your Builds with Bamboo Specs
 
Continuous Load Testing with CloudTest and Jenkins
Continuous Load Testing with CloudTest and JenkinsContinuous Load Testing with CloudTest and Jenkins
Continuous Load Testing with CloudTest and Jenkins
 
Test automation Frame Works
Test automation Frame WorksTest automation Frame Works
Test automation Frame Works
 
An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development
 
CoreData - there is an ORM you can like!
CoreData - there is an ORM you can like!CoreData - there is an ORM you can like!
CoreData - there is an ORM you can like!
 
Implement BDD with Cucumber and SpecFlow
Implement BDD with Cucumber and SpecFlowImplement BDD with Cucumber and SpecFlow
Implement BDD with Cucumber and SpecFlow
 
Defensive Apex Programming
Defensive Apex ProgrammingDefensive Apex Programming
Defensive Apex Programming
 
Agile Data Science on Greenplum Using Airflow - Greenplum Summit 2019
Agile Data Science on Greenplum Using Airflow - Greenplum Summit 2019Agile Data Science on Greenplum Using Airflow - Greenplum Summit 2019
Agile Data Science on Greenplum Using Airflow - Greenplum Summit 2019
 
Getting your mobile test automation process in place - using Cucumber and Cal...
Getting your mobile test automation process in place - using Cucumber and Cal...Getting your mobile test automation process in place - using Cucumber and Cal...
Getting your mobile test automation process in place - using Cucumber and Cal...
 
Scaling Ride-Hailing with Machine Learning on MLflow
Scaling Ride-Hailing with Machine Learning on MLflowScaling Ride-Hailing with Machine Learning on MLflow
Scaling Ride-Hailing with Machine Learning on MLflow
 

More from mtoppa

RubyConf 2022 - From beginner to expert, and back again
RubyConf 2022 - From beginner to expert, and back againRubyConf 2022 - From beginner to expert, and back again
RubyConf 2022 - From beginner to expert, and back againmtoppa
 
RailsConf 2022 - Upgrading Rails: The Dual Boot Way
RailsConf 2022 - Upgrading Rails: The Dual Boot WayRailsConf 2022 - Upgrading Rails: The Dual Boot Way
RailsConf 2022 - Upgrading Rails: The Dual Boot Waymtoppa
 
Applying Omotenashi (Japanese customer service) to your work
Applying Omotenashi (Japanese customer service) to your workApplying Omotenashi (Japanese customer service) to your work
Applying Omotenashi (Japanese customer service) to your workmtoppa
 
Talking to strangers causes train wrecks
Talking to strangers causes train wrecksTalking to strangers causes train wrecks
Talking to strangers causes train wrecksmtoppa
 
A11Y? I18N? L10N? UTF8? WTF? Understanding the connections between: accessib...
A11Y? I18N? L10N? UTF8? WTF? Understanding the connections between:  accessib...A11Y? I18N? L10N? UTF8? WTF? Understanding the connections between:  accessib...
A11Y? I18N? L10N? UTF8? WTF? Understanding the connections between: accessib...mtoppa
 
The promise and peril of Agile and Lean practices
The promise and peril of Agile and Lean practicesThe promise and peril of Agile and Lean practices
The promise and peril of Agile and Lean practicesmtoppa
 
Why do planes crash? Lessons for junior and senior developers
Why do planes crash? Lessons for junior and senior developersWhy do planes crash? Lessons for junior and senior developers
Why do planes crash? Lessons for junior and senior developersmtoppa
 
Boston Ruby Meetup: The promise and peril of Agile and Lean practices
Boston Ruby Meetup: The promise and peril of Agile and Lean practicesBoston Ruby Meetup: The promise and peril of Agile and Lean practices
Boston Ruby Meetup: The promise and peril of Agile and Lean practicesmtoppa
 
A real-life overview of Agile and Scrum
A real-life overview of Agile and ScrumA real-life overview of Agile and Scrum
A real-life overview of Agile and Scrummtoppa
 
WordCamp Nashville 2016: The promise and peril of Agile and Lean practices
WordCamp Nashville 2016: The promise and peril of Agile and Lean practicesWordCamp Nashville 2016: The promise and peril of Agile and Lean practices
WordCamp Nashville 2016: The promise and peril of Agile and Lean practicesmtoppa
 
WordCamp US: Clean Code
WordCamp US: Clean CodeWordCamp US: Clean Code
WordCamp US: Clean Codemtoppa
 
Dependency Injection for PHP
Dependency Injection for PHPDependency Injection for PHP
Dependency Injection for PHPmtoppa
 
WordCamp Boston 2015: Agile Contracts for WordPress Consultants
WordCamp Boston 2015: Agile Contracts for WordPress ConsultantsWordCamp Boston 2015: Agile Contracts for WordPress Consultants
WordCamp Boston 2015: Agile Contracts for WordPress Consultantsmtoppa
 
WordCamp Nashville 2015: Agile Contracts for WordPress Consultants
WordCamp Nashville 2015: Agile Contracts for WordPress ConsultantsWordCamp Nashville 2015: Agile Contracts for WordPress Consultants
WordCamp Nashville 2015: Agile Contracts for WordPress Consultantsmtoppa
 
WordCamp Lancaster 2014: A11Y? I18N? L10N? UTF8? WTF?
WordCamp Lancaster 2014: A11Y? I18N? L10N? UTF8? WTF?WordCamp Lancaster 2014: A11Y? I18N? L10N? UTF8? WTF?
WordCamp Lancaster 2014: A11Y? I18N? L10N? UTF8? WTF?mtoppa
 
WordCamp Nashville: Clean Code for WordPress
WordCamp Nashville: Clean Code for WordPressWordCamp Nashville: Clean Code for WordPress
WordCamp Nashville: Clean Code for WordPressmtoppa
 
A real-life overview of Agile workflow practices
A real-life overview of Agile workflow practicesA real-life overview of Agile workflow practices
A real-life overview of Agile workflow practicesmtoppa
 
Why Agile? Why Now?
Why Agile? Why Now?Why Agile? Why Now?
Why Agile? Why Now?mtoppa
 
Object Oriented Programming for WordPress Plugin Development
Object Oriented Programming for WordPress Plugin DevelopmentObject Oriented Programming for WordPress Plugin Development
Object Oriented Programming for WordPress Plugin Developmentmtoppa
 
Dependency Injection for Wordpress
Dependency Injection for WordpressDependency Injection for Wordpress
Dependency Injection for Wordpressmtoppa
 

More from mtoppa (20)

RubyConf 2022 - From beginner to expert, and back again
RubyConf 2022 - From beginner to expert, and back againRubyConf 2022 - From beginner to expert, and back again
RubyConf 2022 - From beginner to expert, and back again
 
RailsConf 2022 - Upgrading Rails: The Dual Boot Way
RailsConf 2022 - Upgrading Rails: The Dual Boot WayRailsConf 2022 - Upgrading Rails: The Dual Boot Way
RailsConf 2022 - Upgrading Rails: The Dual Boot Way
 
Applying Omotenashi (Japanese customer service) to your work
Applying Omotenashi (Japanese customer service) to your workApplying Omotenashi (Japanese customer service) to your work
Applying Omotenashi (Japanese customer service) to your work
 
Talking to strangers causes train wrecks
Talking to strangers causes train wrecksTalking to strangers causes train wrecks
Talking to strangers causes train wrecks
 
A11Y? I18N? L10N? UTF8? WTF? Understanding the connections between: accessib...
A11Y? I18N? L10N? UTF8? WTF? Understanding the connections between:  accessib...A11Y? I18N? L10N? UTF8? WTF? Understanding the connections between:  accessib...
A11Y? I18N? L10N? UTF8? WTF? Understanding the connections between: accessib...
 
The promise and peril of Agile and Lean practices
The promise and peril of Agile and Lean practicesThe promise and peril of Agile and Lean practices
The promise and peril of Agile and Lean practices
 
Why do planes crash? Lessons for junior and senior developers
Why do planes crash? Lessons for junior and senior developersWhy do planes crash? Lessons for junior and senior developers
Why do planes crash? Lessons for junior and senior developers
 
Boston Ruby Meetup: The promise and peril of Agile and Lean practices
Boston Ruby Meetup: The promise and peril of Agile and Lean practicesBoston Ruby Meetup: The promise and peril of Agile and Lean practices
Boston Ruby Meetup: The promise and peril of Agile and Lean practices
 
A real-life overview of Agile and Scrum
A real-life overview of Agile and ScrumA real-life overview of Agile and Scrum
A real-life overview of Agile and Scrum
 
WordCamp Nashville 2016: The promise and peril of Agile and Lean practices
WordCamp Nashville 2016: The promise and peril of Agile and Lean practicesWordCamp Nashville 2016: The promise and peril of Agile and Lean practices
WordCamp Nashville 2016: The promise and peril of Agile and Lean practices
 
WordCamp US: Clean Code
WordCamp US: Clean CodeWordCamp US: Clean Code
WordCamp US: Clean Code
 
Dependency Injection for PHP
Dependency Injection for PHPDependency Injection for PHP
Dependency Injection for PHP
 
WordCamp Boston 2015: Agile Contracts for WordPress Consultants
WordCamp Boston 2015: Agile Contracts for WordPress ConsultantsWordCamp Boston 2015: Agile Contracts for WordPress Consultants
WordCamp Boston 2015: Agile Contracts for WordPress Consultants
 
WordCamp Nashville 2015: Agile Contracts for WordPress Consultants
WordCamp Nashville 2015: Agile Contracts for WordPress ConsultantsWordCamp Nashville 2015: Agile Contracts for WordPress Consultants
WordCamp Nashville 2015: Agile Contracts for WordPress Consultants
 
WordCamp Lancaster 2014: A11Y? I18N? L10N? UTF8? WTF?
WordCamp Lancaster 2014: A11Y? I18N? L10N? UTF8? WTF?WordCamp Lancaster 2014: A11Y? I18N? L10N? UTF8? WTF?
WordCamp Lancaster 2014: A11Y? I18N? L10N? UTF8? WTF?
 
WordCamp Nashville: Clean Code for WordPress
WordCamp Nashville: Clean Code for WordPressWordCamp Nashville: Clean Code for WordPress
WordCamp Nashville: Clean Code for WordPress
 
A real-life overview of Agile workflow practices
A real-life overview of Agile workflow practicesA real-life overview of Agile workflow practices
A real-life overview of Agile workflow practices
 
Why Agile? Why Now?
Why Agile? Why Now?Why Agile? Why Now?
Why Agile? Why Now?
 
Object Oriented Programming for WordPress Plugin Development
Object Oriented Programming for WordPress Plugin DevelopmentObject Oriented Programming for WordPress Plugin Development
Object Oriented Programming for WordPress Plugin Development
 
Dependency Injection for Wordpress
Dependency Injection for WordpressDependency Injection for Wordpress
Dependency Injection for Wordpress
 

Recently uploaded

#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 

Recently uploaded (20)

#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 

Rails testing: factories or fixtures?

  • 1. Philly.rb meetup Rails testing: factories or fixtures? factories or Michael Toppa March 11, 2014 @mtoppa
  • 2. Why use factories or fixtures? ❖ Factories and fixtures can simplify otherwise repetitive and complex data setup for tests ❖ Your need for them in unit tests will be light if you do TDD with loosely-coupled code ❖ But they are vital for unit-“ish” testing if you’re working with tightly coupled code ❖ e.g. most Rails apps, and the examples in this presentation ❖ They are great for integration testing
  • 3. Comparisons ❖ Tests with no factories or fixtures ❖ Tests with fixtures ❖ Tests with factories, using FactoryGirl ❖ We’ll test the same method in each case, so you can clearly see the differences
  • 4. Partial data model for our examples CandidateCandidate (politician)(politician) RaceRaceCampaignCampaign OfficeOffice CurrentCurrent HoldersHolders Winning Campaign
  • 6. Tests with no factories or fixtures
  • 7. Ok for simple cases # spec/models/candidate_spec.rb describe Candidate do describe "#calculate_completeness" do it "returns 0 when no fields are filled out" do toppa = Candidate.new toppa.calculate_completeness.should eq(0.0) end it "returns a ratio of filled-out fields to total fields" do toppa = Candidate.new toppa.name = "Mike Toppa" toppa.facebook_url = "https://facebook/ElJefe" toppa.wikipedia_url = "http://en.wikipedia.org/wiki/Mike_Toppa" toppa.calculate_completeness.should eq(0.2) # 3 / 15 = 0.2 end end
  • 8. Not so good for complex cases# spec/models/race_spec.rb describe Race do describe '#inaugurate!' do it 'makes Mike Toppa President of the United States' do toppa = Candidate.create( name: 'Mike Toppa', [and all required attributes] ) president = Office.create( title: 'President of the United States', [and all required attributes] ) presidential_race = Race.create([president + all req attrs]) toppa_campaign = Campaign.create([toppa + presidential_race + all req attrs]) presidential_race.winning_campaign = toppa_campaign presidential_race.inaugurate! president.current_holders.first.should == toppa end end end
  • 10. The fixture files # spec/fixtures/candidates.yml mike_toppa: id: 1 name: Mike Toppa gender: M [etc…] # spec/fixtures/office.yml president: id: 1 title: President of the United States level: N [etc…] # spec/fixtures/race.yml president_race_2012: id: 1 office: president election_day: 10/4/2012 [etc…] # spec/fixtures/campaign.yml toppa_us_president_campaign_2012: id: 1 race: president_race_2012 candidate: mike_toppa fec_id: XYZ
  • 11. The test file # spec/models/race_spec.rb describe Race do describe '#inaugurate!' do it 'makes Mike Toppa President of the United States' do toppa = candidates(:mike_toppa) president = offices(:president) presidential_race = races(:us_president_race_2012) toppa_campaign = campaigns(:toppa_us_president_campaign_2012) presidential_race.winning_campaign = toppa_campaign presidential_race.inaugurate! president.current_holders.first.should == toppa end end end
  • 12. Pros ❖ For simple scenarios, re-usable across tests ❖ Easy to generate from live data ❖ Fixture files are easy to read ❖ Tests are fairly fast ❖ Records are inserted based on the fixture files, bypassing ActiveRecord
  • 13. Cons ❖ Brittle ❖ If you add required fields to a model, you have to update all its fixtures ❖ Fixture files are an external dependency ❖ Fixtures are organized by model - you need to keep track of their relationships with test scenarios ❖ Not dynamic - you get the same values every time ❖ (this may or may not be ok)
  • 14. Tests with factories, using FactoryGirl using FactoryGirl
  • 15. The factory files # spec/factories/candidates.rb FactoryGirl.define do factory :candidate do name 'Jane Doe' gender 'F' [etc…] # spec/factories/offices.rb FactoryGirl.define do factory :office do title 'Senator' level 'N' [etc…] # spec/factories/races.rb FactoryGirl.define do factory :race do office election_day '11/04/2014'.to_datetime [etc…] # spec/factories/campaigns.rb FactoryGirl.define do factory :campaign do candidate race fec_id 'XYZ'
  • 16. The test file # spec/models/race_spec.rb describe Race do describe '#inaugurate!' do it 'makes Mike Toppa President of the United States' do toppa = create :candidate, name: 'Mike Toppa' president = create( :office, title: 'President of the United States' ) presidential_race = create :race, office: president toppa_campaign = create( :campaign, candidate: toppa, race: presidential_race ) presidential_race.winning_campaign = toppa_campaign presidential_race.inaugurate! president.current_holders.first.should == toppa end end end
  • 18. Randomized values with the Faker gem # spec/factories/candidates.rb FactoryGirl.define do factory :candidate do name { Faker::Name.name } wikipedia_url { Faker::Internet.url } short_bio { Faker::Lorem.paragraph } phone { Faker::PhoneNumber.phone_number} address_1 { Faker::Address.street_address } address_2 { Faker::Address.secondary_address } city { Faker::Address.city } state { Faker::Address.state } zip { Faker::Address.zip_code } # and other kinds of randomized values gender { |n| %w[M F].sample } sequence(:pvs_id) azavea_updated_at { Time.at(rand * Time.now.to_i) } [etc…]
  • 19. Debate on randomized values ❖ Argument for: ❖ Having a wide variety of values, and combinations of values, in your tests can expose bugs you might otherwise miss ❖ Argument against: ❖ In a test using many different model instances, failures can be difficult to reproduce and debug ❖ If you’re counting on randomized values to find bugs, your design process may not be robust
  • 20. Instantiation options ❖ create: saves your object to the database, and saves any associated objects to the database ❖ build: builds your object in memory only, but still saves any associated objects to the database ❖ build_stubbed: builds your object in memory only, as well as any associated objects
  • 21. Instantiation options ❖ Use build_stubbed whenever possible - your tests will be faster! ❖ You will need to use create or build for integration testing ❖ …and if you’re stuck with tightly coupled Rails code
  • 22. For frequent scenarios: child factories # spec/factories/offices.rb FactoryGirl.define do factory :office do title 'Mayor' level 'L' [etc…] factory :office_president do status 'A' title 'President of the United States' level 'N' [etc…] end end end # spec/models/race_spec.rb describe Race do describe '#inaugurate!' do it 'makes Mike Toppa President of the United States' do president = create :office_president [etc…] end end end
  • 23. Child factories using other child factories # spec/factories/offices.rb FactoryGirl.define do factory :office do area title 'Mayor' level 'L' [etc…] factory :office_house do association :area, factory: :congressional_district status 'A' level 'N' type_code 'H' [etc…] end end end
  • 24. For frequent scenarios: traits # spec/factories/candidates.rb FactoryGirl.define do factory :candidate do name 'Jane Doe' gender 'F' [etc…] end trait :with_office_house do after :create do |candidate| office = create :office_house create :current_office_holder, :office => office, :candidate => candidate end end end # spec/models/race_spec.rb describe Race do describe '#inaugurate!' do it 'makes Mike Toppa President of the United States' do toppa = create: candidate, :with_office_house [etc…] end end end
  • 25. Don’t overuse child factories and traits - leads to brittleness
  • 26. Factories address shortcomings of fixtures ❖ Not as brittle ❖ Factory won’t break if you add a new required field to a model ❖ You don’t need to maintain complex scenarios spread out across fixture files ❖ Lessened external dependency, more flexibility ❖ You can define the attributes important to the test in the test code itself ❖ When using build_stubbed your tests will be faster ❖ But fixtures are faster when inserting records

Editor's Notes

  1. Introductions to using tools usually have overly-simple examples. We’re going to use more realistic examples, as you can only get a feel for the differences between factories and fixtures when dealing with more complex scenarios.
  2. The method we’ll examine is for inaugurating a new office holder, and we’ll make me President of the United States
  3. Fast, simple, clear (not hitting the database)
  4. Specifying all the attributes is cumbersome and when reading the test, distracts from understanding the purpose of the test Brittle: if add a required field to a model, you have to update all the tests using that model Hard to reuse
  5. For each model’s fixture file, you can have multiple records defined updated_at and created_at are set automatically with the current time, or you can specify them
  6. A simple factory file can look a lot like a fixture file…
  7. … but a key difference is that you can override values and specify associations when writing the test