Skip to content

Instantly share code, notes, and snippets.

@jeffcarbs
Last active September 29, 2019 06:13
Show Gist options
  • Save jeffcarbs/bc988c4b08aa81e013d22e8feb11c476 to your computer and use it in GitHub Desktop.
Save jeffcarbs/bc988c4b08aa81e013d22e8feb11c476 to your computer and use it in GitHub Desktop.
Performance issues with FactoryBot traits
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem "factory_bot", "~> 5.0"
end
require 'factory_bot'
require 'benchmark'
class Location
def initialize(city:, state:, country:)
@city = city
@state = state
@country = country
end
end
FactoryBot.define do
factory(:factory_with_no_traits, class: 'Location') do
city { 'Denver' }
state { 'CO' }
country { 'USA' }
initialize_with do
new(attributes)
end
end
factory(:factory_with_one_trait, class: 'Location') do
city { 'Denver' }
state { 'CO' }
country { 'USA' }
trait(:no_country) { country { nil } }
initialize_with do
new(attributes)
end
end
factory(:factory_with_two_traits, class: 'Location') do
city { 'Denver' }
state { 'CO' }
country { 'USA' }
trait(:no_country) { country { nil } }
trait(:no_state) { state { nil } }
initialize_with do
new(attributes)
end
end
factory(:factory_with_three_traits, class: 'Location') do
city { 'Denver' }
state { 'CO' }
country { 'USA' }
trait(:no_country) { country { nil } }
trait(:no_state) { state { nil } }
trait(:no_city) { state { nil } }
initialize_with do
new(attributes)
end
end
factory(:factory_with_fifty_traits, class: 'Location') do
city { 'Denver' }
state { 'CO' }
country { 'USA' }
trait(:ak) { state { 'AK' } }
trait(:al) { state { 'AL' } }
trait(:ar) { state { 'AR' } }
trait(:az) { state { 'AZ' } }
trait(:ca) { state { 'CA' } }
trait(:co) { state { 'CO' } }
trait(:ct) { state { 'CT' } }
trait(:dc) { state { 'DC' } }
trait(:de) { state { 'DE' } }
trait(:fl) { state { 'FL' } }
trait(:ga) { state { 'GA' } }
trait(:hi) { state { 'HI' } }
trait(:ia) { state { 'IA' } }
trait(:id) { state { 'ID' } }
trait(:il) { state { 'IL' } }
trait(:in) { state { 'IN' } }
trait(:ks) { state { 'KS' } }
trait(:ky) { state { 'KY' } }
trait(:la) { state { 'LA' } }
trait(:ma) { state { 'MA' } }
trait(:md) { state { 'MD' } }
trait(:me) { state { 'ME' } }
trait(:mi) { state { 'MI' } }
trait(:mn) { state { 'MN' } }
trait(:mo) { state { 'MO' } }
trait(:ms) { state { 'MS' } }
trait(:mt) { state { 'MT' } }
trait(:nc) { state { 'NC' } }
trait(:nd) { state { 'ND' } }
trait(:ne) { state { 'NE' } }
trait(:nh) { state { 'NH' } }
trait(:nj) { state { 'NJ' } }
trait(:nm) { state { 'NM' } }
trait(:nv) { state { 'NV' } }
trait(:ny) { state { 'NY' } }
trait(:oh) { state { 'OH' } }
trait(:ok) { state { 'OK' } }
trait(:or) { state { 'OR' } }
trait(:pa) { state { 'PA' } }
trait(:ri) { state { 'RI' } }
trait(:sc) { state { 'SC' } }
trait(:sd) { state { 'SD' } }
trait(:tn) { state { 'TN' } }
trait(:tx) { state { 'TX' } }
trait(:ut) { state { 'UT' } }
trait(:va) { state { 'VA' } }
trait(:vt) { state { 'VT' } }
trait(:wa) { state { 'WA' } }
trait(:wi) { state { 'WI' } }
trait(:wv) { state { 'WV' } }
trait(:wy) { state { 'WY' } }
initialize_with do
new(attributes)
end
end
end
n = 10000
puts "Test one (n=#{n}): not setting anything"
Benchmark.bm do |x|
x.report('Has 0 traits') { n.times { FactoryBot.build(:factory_with_no_traits) } }
x.report('Has 1 trait ') { n.times { FactoryBot.build(:factory_with_one_trait) } }
x.report('Has 2 traits') { n.times { FactoryBot.build(:factory_with_two_traits) } }
x.report('Has 3 traits') { n.times { FactoryBot.build(:factory_with_three_traits) } }
x.report('Has 50 traits') { n.times { FactoryBot.build(:factory_with_fifty_traits) } }
end
puts
puts "Test two (n=#{n}): passing attributes without using traits"
Benchmark.bm do |x|
x.report('Has 0 traits') { n.times { FactoryBot.build(:factory_with_no_traits, city: 'New York', state: 'NY') } }
x.report('Has 1 trait ') { n.times { FactoryBot.build(:factory_with_one_trait, city: 'New York', state: 'NY') } }
x.report('Has 2 traits') { n.times { FactoryBot.build(:factory_with_two_traits, city: 'New York', state: 'NY') } }
x.report('Has 3 traits') { n.times { FactoryBot.build(:factory_with_three_traits, city: 'New York', state: 'NY') } }
x.report('Has 50 traits') { n.times { FactoryBot.build(:factory_with_fifty_traits, city: 'New York', state: 'NY') } }
end
puts
puts "Test three (n=#{n}): passing attributes and using traits"
Benchmark.bm do |x|
x.report('Has 0 traits, using 0') { n.times { FactoryBot.build(:factory_with_no_traits, city: 'New York', state: 'NY') } }
x.report('Has 1 trait, using 1 ') { n.times { FactoryBot.build(:factory_with_one_trait, :no_country, city: 'New York', state: 'NY') } }
x.report('Has 2 traits, using 1 ') { n.times { FactoryBot.build(:factory_with_two_traits, :no_country, city: 'New York', state: 'NY') } }
x.report('Has 3 traits, using 1 ') { n.times { FactoryBot.build(:factory_with_three_traits, :no_country, city: 'New York', state: 'NY') } }
x.report('Has 50 traits, using 1 ') { n.times { FactoryBot.build(:factory_with_fifty_traits, :ny, city: 'New York') } }
end
puts
puts "Test three (n=#{n}): using traits without passing attributes"
Benchmark.bm do |x|
x.report('Has 0 traits, using 0') { n.times { FactoryBot.build(:factory_with_no_traits) } }
x.report('Has 1 trait, using 1 ') { n.times { FactoryBot.build(:factory_with_one_trait, :no_country) } }
x.report('Has 2 traits, using 1 ') { n.times { FactoryBot.build(:factory_with_two_traits, :no_country) } }
x.report('Has 3 traits, using 1 ') { n.times { FactoryBot.build(:factory_with_three_traits, :no_country) } }
x.report('Has 50 traits, using 1 ') { n.times { FactoryBot.build(:factory_with_fifty_traits, :ny) } }
end
puts
puts "Test five (n=#{n}): using different amounts of traits on factory with a 3 traits without passing attributes"
Benchmark.bm do |x|
x.report('Has 3 traits, using 1') { n.times { FactoryBot.build(:factory_with_three_traits, :no_city) } }
x.report('Has 3 traits, using 2') { n.times { FactoryBot.build(:factory_with_three_traits, :no_city, :no_state) } }
x.report('Has 3 traits, using 3') { n.times { FactoryBot.build(:factory_with_three_traits, :no_city, :no_state, :no_country) } }
end
puts
puts "Test five (n=#{n}): using different amounts of traits on factory with 50 traits without passing attributes"
Benchmark.bm do |x|
x.report('Has 50 traits, using 1') { n.times { FactoryBot.build(:factory_with_fifty_traits, :ny) } }
x.report('Has 50 traits, using 2') { n.times { FactoryBot.build(:factory_with_fifty_traits, :ny, :co) } }
x.report('Has 50 traits, using 3') { n.times { FactoryBot.build(:factory_with_fifty_traits, :ny, :co, :ca) } }
x.report('Has 50 traits, using 4') { n.times { FactoryBot.build(:factory_with_fifty_traits, :ny, :co, :ca, :ia) } }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment