Commit
Factory Girl now allows factories to override object instantiation. This means factories can use factory methods (e.g. methods other than new) as well as pass arguments explicitly. factory :user do ignore do things { ["thing 1", "thing 2"] } end initialize_with { User.construct_with_things(things) } end factory :report_generator do ignore do name { "Generic Report" } data { {:foo => "bar", :baz => "buzz"} } end initialize_with { ReportGenerator.new(name, data) } end Whitespace Code recommendations
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -590,6 +590,42 @@ To set the attributes for each of the factories, you can pass in a hash as you n | |
twenty_year_olds = FactoryGirl.build_list(:user, 25, :date_of_birth => 20.years.ago) | ||
``` | ||
|
||
Custom Construction | ||
------------------- | ||
|
||
Instantiating objects can be overridden in the case where you'd rather not | ||
call `new` on your build class or you have some other factory method that | ||
you'd prefer to use. Using custom construction also allows for your objects to | ||
be instantiated with any number of arguments. | ||
|
||
```ruby | ||
# user.rb | ||
class User | ||
attr_accessor :name, :email | ||
|
||
def initialize(name) | ||
@name = name | ||
end | ||
end | ||
|
||
# factories.rb | ||
sequence(:name) {|n| "person#{n}@example.com" } | ||
This comment has been minimized.
Sorry, something went wrong. |
||
|
||
factory :user do | ||
ignore do | ||
name { Faker::Name.name } | ||
end | ||
|
||
initialize_with { User.new(name) } | ||
end | ||
|
||
FactoryGirl.build(:user).name # Bob Hope | ||
``` | ||
|
||
Notice that I ignored the `name` attribute. If you don't want attributes | ||
reassigned after your object has been instantiated, you'll want to `ignore` them. | ||
|
||
This comment has been minimized.
Sorry, something went wrong.
r00k
Contributor
|
||
Cucumber Integration | ||
-------------------- | ||
|
||
|
@@ -620,4 +656,4 @@ User.blueprint do | |
end | ||
|
||
User.make(:name => 'Johnny') | ||
``` | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
require "spec_helper" | ||
|
||
describe "initialize_with with non-FG attributes" do | ||
include FactoryGirl::Syntax::Methods | ||
|
||
before do | ||
define_model("User", :name => :string, :age => :integer) do | ||
def self.construct(name, age) | ||
new(:name => name, :age => age) | ||
end | ||
end | ||
|
||
FactoryGirl.define do | ||
factory :user do | ||
initialize_with { User.construct("John Doe", 21) } | ||
end | ||
end | ||
end | ||
|
||
subject { build(:user) } | ||
its(:name) { should == "John Doe" } | ||
its(:age) { should == 21 } | ||
end | ||
|
||
describe "initialize_with with FG attributes that are ignored" do | ||
include FactoryGirl::Syntax::Methods | ||
|
||
before do | ||
define_model("User", :name => :string) do | ||
def self.construct(name) | ||
new(:name => "#{name} from .construct") | ||
end | ||
end | ||
|
||
FactoryGirl.define do | ||
factory :user do | ||
ignore do | ||
name { "Handsome Chap" } | ||
end | ||
|
||
initialize_with { User.construct(name) } | ||
end | ||
end | ||
end | ||
|
||
subject { build(:user) } | ||
its(:name) { should == "Handsome Chap from .construct" } | ||
end | ||
|
||
describe "initialize_with with FG attributes that are not ignored" do | ||
include FactoryGirl::Syntax::Methods | ||
|
||
before do | ||
define_model("User", :name => :string) do | ||
def self.construct(name) | ||
new(:name => "#{name} from .construct") | ||
end | ||
end | ||
|
||
FactoryGirl.define do | ||
factory :user do | ||
name { "Handsome Chap" } | ||
|
||
initialize_with { User.construct(name) } | ||
end | ||
end | ||
end | ||
|
||
it "assigns each attribute even if the attribute has been used in the constructor" do | ||
build(:user).name.should == "Handsome Chap" | ||
end | ||
end | ||
|
||
describe "initialize_with non-ORM-backed objects" do | ||
include FactoryGirl::Syntax::Methods | ||
|
||
before do | ||
define_class("ReportGenerator") do | ||
attr_reader :name, :data | ||
|
||
def initialize(name, data) | ||
@name = name | ||
@data = data | ||
end | ||
end | ||
|
||
FactoryGirl.define do | ||
sequence(:random_data) { 5.times.map { Kernel.rand(200) } } | ||
|
||
factory :report_generator do | ||
ignore do | ||
name "My Awesome Report" | ||
end | ||
|
||
initialize_with { ReportGenerator.new(name, FactoryGirl.generate(:random_data)) } | ||
end | ||
end | ||
end | ||
|
||
it "allows for overrides" do | ||
build(:report_generator, :name => "Overridden").name.should == "Overridden" | ||
end | ||
|
||
it "generates random data" do | ||
build(:report_generator).data.length.should == 5 | ||
end | ||
end | ||
|
||
describe "initialize_with parent and child factories" do | ||
before do | ||
define_class("Awesome") do | ||
attr_reader :name | ||
|
||
def initialize(name) | ||
@name = name | ||
end | ||
end | ||
|
||
FactoryGirl.define do | ||
factory :awesome do | ||
ignore do | ||
name "Great" | ||
end | ||
|
||
initialize_with { Awesome.new(name) } | ||
|
||
factory :sub_awesome do | ||
ignore do | ||
name "Sub" | ||
end | ||
end | ||
|
||
factory :super_awesome do | ||
initialize_with { Awesome.new("Super") } | ||
end | ||
end | ||
end | ||
end | ||
|
||
it "uses the parent's constructor when the child factory doesn't assign it" do | ||
FactoryGirl.build(:sub_awesome).name.should == "Sub" | ||
end | ||
|
||
it "allows child factories to override initialize_with" do | ||
FactoryGirl.build(:super_awesome).name.should == "Super" | ||
end | ||
end |
Doesn't look like a name sequence.