-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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.