mirror of
https://github.com/thoughtbot/factory_bot.git
synced 2022-11-09 11:43:51 -05:00
Traits can be added to factories when the factory creates an instance
This allows for traits to be used with normal factories without having to name every single factory that uses one (or many) traits. So, instead of creating male_admin and female_admin factories: FactoryGirl.define do factory :user do trait(:admin) { admin true } trait(:male) { gender "Male" } trait(:female) { gender "Female" } factory :male_admin, :traits => [:male, :admin] factory :female_admin, :traits => [:admin, :female] end end FactoryGirl.create(:male_admin) FactoryGirl.create(:female_admin) You could just create a user with those traits assigned: FactoryGirl.create(:user, :admin, :male) FactoryGirl.create(:user, :admin, :female) This can be combined with attribute overrides as expected. FactoryGirl.create(:user, :admin, :male, :name => "John Doe") FactoryGirl.create(:user, :admin, :female, :name => "Jane Doe")
This commit is contained in:
parent
845a76a595
commit
442ba18f14
5 changed files with 143 additions and 16 deletions
|
@ -404,6 +404,26 @@ You can also override individual attributes granted by a trait in subclasses.
|
|||
end
|
||||
end
|
||||
|
||||
Traits can also be passed in as a list of symbols when you construct an instance from FactoryGirl.
|
||||
|
||||
factory :user do
|
||||
name "Friendly User"
|
||||
|
||||
trait :male do
|
||||
name "John Doe"
|
||||
gender "Male"
|
||||
end
|
||||
|
||||
trait :admin do
|
||||
admin true
|
||||
end
|
||||
end
|
||||
|
||||
# creates an admin user with gender "Male" and name "Jon Snow"
|
||||
FactoryGirl.create(:user, :admin, :male, :name => "Jon Snow")
|
||||
|
||||
This ability works with `build`, `build_stubbed`, `attributes_for`, and `create`.
|
||||
|
||||
Callbacks
|
||||
---------
|
||||
|
||||
|
|
|
@ -90,6 +90,12 @@ module FactoryGirl
|
|||
@definition.compile
|
||||
end
|
||||
|
||||
def with_traits(traits)
|
||||
self.clone.tap do |factory_with_traits|
|
||||
factory_with_traits.inherit_traits traits
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def class_name #:nodoc:
|
||||
|
@ -132,6 +138,11 @@ module FactoryGirl
|
|||
end
|
||||
end
|
||||
|
||||
def initialize_copy(source)
|
||||
super
|
||||
@definition = @definition.clone
|
||||
end
|
||||
|
||||
class Runner
|
||||
def initialize(options = {})
|
||||
@attributes = options[:attributes]
|
||||
|
|
|
@ -8,16 +8,17 @@ module FactoryGirl
|
|||
# Arguments:
|
||||
# * name: +Symbol+ or +String+
|
||||
# The name of the factory that should be used.
|
||||
# * overrides: +Hash+
|
||||
# Attributes to overwrite for this set.
|
||||
# * traits_and_overrides: +Array+
|
||||
# [+*Array+] Traits to be applied
|
||||
# [+Hash+] Attributes to overwrite for this set.
|
||||
# * block:
|
||||
# Yields the hash of attributes.
|
||||
#
|
||||
# Returns: +Hash+
|
||||
# A set of attributes that can be used to build an instance of the class
|
||||
# this factory generates.
|
||||
def attributes_for(name, overrides = {}, &block)
|
||||
FactoryGirl.factory_by_name(name).run(Proxy::AttributesFor, overrides, &block)
|
||||
def attributes_for(name, *traits_and_overrides, &block)
|
||||
run_factory_girl_proxy(name, traits_and_overrides, Proxy::AttributesFor, &block)
|
||||
end
|
||||
|
||||
# Generates and returns an instance from this factory. Attributes can be
|
||||
|
@ -26,16 +27,17 @@ module FactoryGirl
|
|||
# Arguments:
|
||||
# * name: +Symbol+ or +String+
|
||||
# The name of the factory that should be used.
|
||||
# * overrides: +Hash+
|
||||
# Attributes to overwrite for this instance.
|
||||
# * traits_and_overrides: +Array+
|
||||
# [+*Array+] Traits to be applied
|
||||
# [+Hash+] Attributes to overwrite for this instance.
|
||||
# * block:
|
||||
# Yields the built instance.
|
||||
#
|
||||
# Returns: +Object+
|
||||
# An instance of the class this factory generates, with generated attributes
|
||||
# assigned.
|
||||
def build(name, overrides = {}, &block)
|
||||
FactoryGirl.factory_by_name(name).run(Proxy::Build, overrides, &block)
|
||||
def build(name, *traits_and_overrides, &block)
|
||||
run_factory_girl_proxy(name, traits_and_overrides, Proxy::Build, &block)
|
||||
end
|
||||
|
||||
# Generates, saves, and returns an instance from this factory. Attributes can
|
||||
|
@ -48,16 +50,17 @@ module FactoryGirl
|
|||
# Arguments:
|
||||
# * name: +Symbol+ or +String+
|
||||
# The name of the factory that should be used.
|
||||
# * overrides: +Hash+
|
||||
# Attributes to overwrite for this instance.
|
||||
# * traits_and_overrides: +Array+
|
||||
# [+*Array+] Traits to be applied
|
||||
# [+Hash+] Attributes to overwrite for this instance.
|
||||
# * block:
|
||||
# Yields the created instance.
|
||||
#
|
||||
# Returns: +Object+
|
||||
# A saved instance of the class this factory generates, with generated
|
||||
# attributes assigned.
|
||||
def create(name, overrides = {}, &block)
|
||||
FactoryGirl.factory_by_name(name).run(Proxy::Create, overrides, &block)
|
||||
def create(name, *traits_and_overrides, &block)
|
||||
run_factory_girl_proxy(name, traits_and_overrides, Proxy::Create, &block)
|
||||
end
|
||||
|
||||
# Generates and returns an object with all attributes from this factory
|
||||
|
@ -67,15 +70,16 @@ module FactoryGirl
|
|||
# Arguments:
|
||||
# * name: +Symbol+ or +String+
|
||||
# The name of the factory that should be used.
|
||||
# * overrides: +Hash+
|
||||
# Attributes to overwrite for this instance.
|
||||
# * traits_and_overrides: +Array+
|
||||
# [+*Array+] Traits to be applied
|
||||
# [+Hash+] Attributes to overwrite for this instance.
|
||||
# * block
|
||||
# Yields the stubbed object.
|
||||
#
|
||||
# Returns: +Object+
|
||||
# An object with generated attributes stubbed out.
|
||||
def build_stubbed(name, overrides = {}, &block)
|
||||
FactoryGirl.factory_by_name(name).run(Proxy::Stub, overrides, &block)
|
||||
def build_stubbed(name, *traits_and_overrides, &block)
|
||||
run_factory_girl_proxy(name, traits_and_overrides, Proxy::Stub, &block)
|
||||
end
|
||||
|
||||
# Builds and returns multiple instances from this factory as an array. Attributes can be
|
||||
|
@ -125,6 +129,24 @@ module FactoryGirl
|
|||
def generate(name)
|
||||
FactoryGirl.sequence_by_name(name).next
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def run_factory_girl_proxy(name, traits_and_overrides, proxy, &block)
|
||||
overrides = if traits_and_overrides.last.respond_to?(:has_key?)
|
||||
traits_and_overrides.pop
|
||||
else
|
||||
{}
|
||||
end
|
||||
|
||||
factory = FactoryGirl.factory_by_name(name)
|
||||
|
||||
if traits_and_overrides.any?
|
||||
factory = factory.with_traits(traits_and_overrides)
|
||||
end
|
||||
|
||||
factory.run(proxy, overrides, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -200,3 +200,57 @@ describe "traits with callbacks" do
|
|||
its(:name) { should == "JOHN" }
|
||||
end
|
||||
end
|
||||
|
||||
describe "traits added via proxy" do
|
||||
before do
|
||||
define_model("User", :name => :string, :admin => :boolean)
|
||||
|
||||
FactoryGirl.define do
|
||||
factory :user do
|
||||
name "John"
|
||||
|
||||
trait :admin do
|
||||
admin true
|
||||
end
|
||||
|
||||
trait :great do
|
||||
after_create {|user| user.name.upcase! }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "adding traits in create" do
|
||||
subject { FactoryGirl.create(:user, :admin, :great, :name => "Joe") }
|
||||
|
||||
its(:admin) { should be_true }
|
||||
its(:name) { should == "JOE" }
|
||||
|
||||
it "doesn't modify the user factory" do
|
||||
subject
|
||||
FactoryGirl.create(:user).should_not be_admin
|
||||
FactoryGirl.create(:user).name.should == "John"
|
||||
end
|
||||
end
|
||||
|
||||
context "adding traits in build" do
|
||||
subject { FactoryGirl.build(:user, :admin, :great, :name => "Joe") }
|
||||
|
||||
its(:admin) { should be_true }
|
||||
its(:name) { should == "Joe" }
|
||||
end
|
||||
|
||||
context "adding traits in attributes_for" do
|
||||
subject { FactoryGirl.attributes_for(:user, :admin, :great) }
|
||||
|
||||
its([:admin]) { should be_true }
|
||||
its([:name]) { should == "John" }
|
||||
end
|
||||
|
||||
context "adding traits in build_stubbed" do
|
||||
subject { FactoryGirl.build_stubbed(:user, :admin, :great, :name => "Jack") }
|
||||
|
||||
its(:admin) { should be_true }
|
||||
its(:name) { should == "Jack" }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -286,3 +286,23 @@ describe FactoryGirl::Factory, "running a factory" do
|
|||
block_run.should == "changed"
|
||||
end
|
||||
end
|
||||
|
||||
describe FactoryGirl::Factory, "#with_traits" do
|
||||
subject { FactoryGirl::Factory.new(:user) }
|
||||
let(:admin_trait) { FactoryGirl::Trait.new(:admin) }
|
||||
let(:female_trait) { FactoryGirl::Trait.new(:female) }
|
||||
|
||||
before do
|
||||
FactoryGirl.register_trait(admin_trait)
|
||||
FactoryGirl.register_trait(female_trait)
|
||||
end
|
||||
|
||||
it "returns a factory with the correct traits" do
|
||||
subject.with_traits([:admin, :female]).traits.should =~ [admin_trait, female_trait]
|
||||
end
|
||||
|
||||
it "doesn't modify the original factory's traits" do
|
||||
subject.with_traits([:admin, :female])
|
||||
subject.traits.should be_empty
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue