Allow child factories to be defined by nesting
This commit is contained in:
parent
4d8d419375
commit
0c0699759f
|
@ -133,7 +133,21 @@ The behavior of the association method varies depending on the build strategy us
|
|||
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
|
||||
title 'A title'
|
||||
|
@ -143,9 +157,11 @@ You can easily create multiple factories for the same class without repeating co
|
|||
approved true
|
||||
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
|
||||
---------
|
||||
|
|
|
@ -4,8 +4,11 @@ module FactoryGirl
|
|||
undef_method(method) unless method =~ /(^__|^nil\?$|^send$|^object_id$|^extend$|^instance_eval$)/
|
||||
end
|
||||
|
||||
attr_reader :child_factories
|
||||
|
||||
def initialize(factory)
|
||||
@factory = factory
|
||||
@child_factories = []
|
||||
end
|
||||
|
||||
# Adds an attribute that should be assigned on generated instances for this
|
||||
|
@ -143,5 +146,9 @@ module FactoryGirl
|
|||
def to_create(&block)
|
||||
@factory.to_create(&block)
|
||||
end
|
||||
|
||||
def factory(name, options = {}, &block)
|
||||
@child_factories << [name, options, block]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,6 +20,10 @@ module FactoryGirl
|
|||
factory.inherit_from(FactoryGirl.factory_by_name(parent))
|
||||
end
|
||||
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
|
||||
|
||||
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
|
||||
factory :user do
|
||||
name { "John" }
|
||||
email { "john@example.com" }
|
||||
end
|
||||
name "John"
|
||||
email "john@example.com"
|
||||
|
||||
factory :admin, :parent => :user do
|
||||
admin { true }
|
||||
email { "admin@example.com" }
|
||||
factory :admin do
|
||||
admin true
|
||||
email "admin@example.com"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
subject { FactoryGirl.create(:admin) }
|
||||
|
||||
it "uses the parent build class" do
|
||||
subject.should be_kind_of(User)
|
||||
describe "the parent class" do
|
||||
subject { FactoryGirl.create(:user) }
|
||||
it { should_not be_admin }
|
||||
its(:email) { should == "john@example.com" }
|
||||
end
|
||||
|
||||
it "inherits attributes" do
|
||||
subject.name.should == 'John'
|
||||
end
|
||||
|
||||
it "has its own attributes" do
|
||||
subject.should be_admin
|
||||
end
|
||||
|
||||
it "overrides attributes" do
|
||||
subject.email.should == 'admin@example.com'
|
||||
describe "the child class" do
|
||||
subject { FactoryGirl.create(:admin) }
|
||||
it { should be_kind_of(User) }
|
||||
it { should be_admin }
|
||||
its(:name) { should == "John" }
|
||||
its(:email) { should == "admin@example.com" }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -37,6 +37,16 @@ describe FactoryGirl::DefinitionProxy do
|
|||
}.should raise_error(FactoryGirl::AttributeDefinitionError)
|
||||
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
|
||||
it "should create the sequence" do
|
||||
mock(FactoryGirl::Sequence).new(:name, 1)
|
||||
|
|
Loading…
Reference in New Issue