Allow child factories to be defined by nesting

This commit is contained in:
Joshua Clayton 2011-06-29 16:49:45 -04:00
parent 4d8d419375
commit 0c0699759f
5 changed files with 56 additions and 23 deletions

View File

@ -133,7 +133,21 @@ The behavior of the association method varies depending on the build strategy us
Inheritance Inheritance
----------- -----------
You can easily create multiple factories for the same class without repeating common attributes by using inheritance: You can easily create multiple factories for the same class without repeating common attributes by nesting factories:
factory :post do
title 'A title'
factory :approved_post do
approved true
end
end
approved_post = FactoryGirl.create(:approved_post)
approved_post.title # => 'A title'
approved_post.approved # => true
You can also assign the parent explicitly:
factory :post do factory :post do
title 'A title' title 'A title'
@ -143,9 +157,11 @@ You can easily create multiple factories for the same class without repeating co
approved true approved true
end end
FactoryGirl.create(:approved_post).title # => 'A title' approved_post = FactoryGirl.create(:approved_post)
approved_post.title # => 'A title'
approved_post.approved # => true
As mentioned above, it's good practice to define a basic factory for each class with only the attributes required to create it. Then, create more-specific factories that inherit from this basic parent. Factory definitions are still code, so keep them DRY. As mentioned above, it's good practice to define a basic factory for each class with only the attributes required to create it. Then, create more specific factories that inherit from this basic parent. Factory definitions are still code, so keep them DRY.
Sequences Sequences
--------- ---------

View File

@ -4,8 +4,11 @@ module FactoryGirl
undef_method(method) unless method =~ /(^__|^nil\?$|^send$|^object_id$|^extend$|^instance_eval$)/ undef_method(method) unless method =~ /(^__|^nil\?$|^send$|^object_id$|^extend$|^instance_eval$)/
end end
attr_reader :child_factories
def initialize(factory) def initialize(factory)
@factory = factory @factory = factory
@child_factories = []
end end
# Adds an attribute that should be assigned on generated instances for this # Adds an attribute that should be assigned on generated instances for this
@ -143,5 +146,9 @@ module FactoryGirl
def to_create(&block) def to_create(&block)
@factory.to_create(&block) @factory.to_create(&block)
end end
def factory(name, options = {}, &block)
@child_factories << [name, options, block]
end
end end
end end

View File

@ -20,6 +20,10 @@ module FactoryGirl
factory.inherit_from(FactoryGirl.factory_by_name(parent)) factory.inherit_from(FactoryGirl.factory_by_name(parent))
end end
FactoryGirl.register_factory(factory) FactoryGirl.register_factory(factory)
proxy.child_factories.each do |(child_name, child_options, child_block)|
factory(child_name, child_options.merge(:parent => name), &child_block)
end
end end
def sequence(name, start_value = 1, &block) def sequence(name, start_value = 1, &block)

View File

@ -7,33 +7,29 @@ describe "an instance generated by a factory that inherits from another factory"
FactoryGirl.define do FactoryGirl.define do
factory :user do factory :user do
name { "John" } name "John"
email { "john@example.com" } email "john@example.com"
end
factory :admin, :parent => :user do factory :admin do
admin { true } admin true
email { "admin@example.com" } email "admin@example.com"
end
end end
end end
end end
subject { FactoryGirl.create(:admin) } describe "the parent class" do
subject { FactoryGirl.create(:user) }
it "uses the parent build class" do it { should_not be_admin }
subject.should be_kind_of(User) its(:email) { should == "john@example.com" }
end end
it "inherits attributes" do describe "the child class" do
subject.name.should == 'John' subject { FactoryGirl.create(:admin) }
end it { should be_kind_of(User) }
it { should be_admin }
it "has its own attributes" do its(:name) { should == "John" }
subject.should be_admin its(:email) { should == "admin@example.com" }
end
it "overrides attributes" do
subject.email.should == 'admin@example.com'
end end
end end

View File

@ -37,6 +37,16 @@ describe FactoryGirl::DefinitionProxy do
}.should raise_error(FactoryGirl::AttributeDefinitionError) }.should raise_error(FactoryGirl::AttributeDefinitionError)
end end
describe "child factories" do
its(:child_factories) { should == [] }
it "should be able to add child factories" do
block = lambda {}
subject.factory(:admin, { :aliases => [:great] }, &block)
subject.child_factories.should == [[:admin, { :aliases => [:great] }, block]]
end
end
describe "adding an attribute using a in-line sequence" do describe "adding an attribute using a in-line sequence" do
it "should create the sequence" do it "should create the sequence" do
mock(FactoryGirl::Sequence).new(:name, 1) mock(FactoryGirl::Sequence).new(:name, 1)