mirror of
https://github.com/thoughtbot/factory_bot.git
synced 2022-11-09 11:43:51 -05:00
Allow child factories to be defined by nesting
This commit is contained in:
parent
4d8d419375
commit
0c0699759f
5 changed files with 56 additions and 23 deletions
|
@ -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
|
||||||
---------
|
---------
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue