factory_girl 2.3.2 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/.travis.yml +5 -3
  2. data/Appraisals +4 -0
  3. data/CONTRIBUTION_GUIDELINES.md +1 -1
  4. data/Changelog +13 -0
  5. data/GETTING_STARTED.md +362 -286
  6. data/Gemfile.lock +1 -1
  7. data/README.md +8 -8
  8. data/features/factory_girl_steps.feature +4 -0
  9. data/features/support/factories.rb +19 -0
  10. data/gemfiles/2.1.gemfile.lock +1 -1
  11. data/gemfiles/2.3.gemfile.lock +1 -1
  12. data/gemfiles/3.0.gemfile.lock +1 -1
  13. data/gemfiles/3.1.gemfile.lock +1 -1
  14. data/gemfiles/3.2.gemfile +7 -0
  15. data/gemfiles/3.2.gemfile.lock +90 -0
  16. data/lib/factory_girl.rb +4 -0
  17. data/lib/factory_girl/attribute.rb +1 -9
  18. data/lib/factory_girl/attribute/association.rb +2 -2
  19. data/lib/factory_girl/attribute/dynamic.rb +2 -2
  20. data/lib/factory_girl/attribute/sequence.rb +1 -1
  21. data/lib/factory_girl/attribute/static.rb +1 -1
  22. data/lib/factory_girl/attribute_assigner.rb +73 -0
  23. data/lib/factory_girl/attribute_list.rb +6 -15
  24. data/lib/factory_girl/callback.rb +2 -2
  25. data/lib/factory_girl/evaluator.rb +57 -0
  26. data/lib/factory_girl/evaluator_class_definer.rb +34 -0
  27. data/lib/factory_girl/factory.rb +31 -80
  28. data/lib/factory_girl/null_factory.rb +2 -1
  29. data/lib/factory_girl/null_object.rb +19 -0
  30. data/lib/factory_girl/proxy.rb +6 -87
  31. data/lib/factory_girl/proxy/attributes_for.rb +2 -7
  32. data/lib/factory_girl/proxy/build.rb +4 -3
  33. data/lib/factory_girl/proxy/create.rb +6 -7
  34. data/lib/factory_girl/proxy/stub.rb +19 -18
  35. data/lib/factory_girl/step_definitions.rb +4 -3
  36. data/lib/factory_girl/version.rb +1 -1
  37. data/spec/acceptance/aliases_spec.rb +19 -0
  38. data/spec/acceptance/attributes_for_spec.rb +10 -1
  39. data/spec/acceptance/attributes_from_instance_spec.rb +53 -0
  40. data/spec/acceptance/build_spec.rb +8 -0
  41. data/spec/acceptance/build_stubbed_spec.rb +9 -0
  42. data/spec/acceptance/create_spec.rb +8 -0
  43. data/spec/factory_girl/attribute/association_spec.rb +5 -4
  44. data/spec/factory_girl/attribute/dynamic_spec.rb +9 -10
  45. data/spec/factory_girl/attribute/sequence_spec.rb +1 -2
  46. data/spec/factory_girl/attribute/static_spec.rb +1 -2
  47. data/spec/factory_girl/attribute_list_spec.rb +14 -4
  48. data/spec/factory_girl/evaluator_class_definer_spec.rb +54 -0
  49. data/spec/factory_girl/factory_spec.rb +23 -16
  50. data/spec/factory_girl/null_factory_spec.rb +2 -1
  51. data/spec/factory_girl/null_object_spec.rb +8 -0
  52. data/spec/factory_girl/proxy/attributes_for_spec.rb +8 -24
  53. data/spec/factory_girl/proxy/build_spec.rb +1 -7
  54. data/spec/factory_girl/proxy/create_spec.rb +2 -27
  55. data/spec/factory_girl/proxy/stub_spec.rb +14 -13
  56. data/spec/factory_girl/proxy_spec.rb +1 -33
  57. data/spec/support/shared_examples/proxy.rb +22 -45
  58. metadata +133 -177
@@ -114,13 +114,14 @@ FactoryGirl.factories.each do |factory|
114
114
 
115
115
  if factory.build_class.respond_to?(:columns)
116
116
  factory.build_class.columns.each do |column|
117
- human_column_name = column.name.downcase.gsub('_', ' ')
117
+ name = column.respond_to?(:name) ? column.name : column.to_s
118
+ human_column_name = name.downcase.gsub('_', ' ')
118
119
  Given /^an? #{human_name} exists with an? #{human_column_name} of "([^"]*)"$/i do |value|
119
- FactoryGirl.create(factory.name, column.name => value)
120
+ FactoryGirl.create(factory.name, name => value)
120
121
  end
121
122
 
122
123
  Given /^(\d+) #{human_name.pluralize} exist with an? #{human_column_name} of "([^"]*)"$/i do |count, value|
123
- FactoryGirl.create_list(factory.name, count.to_i, column.name => value)
124
+ FactoryGirl.create_list(factory.name, count.to_i, name => value)
124
125
  end
125
126
  end
126
127
  end
@@ -1,4 +1,4 @@
1
1
  module FactoryGirl
2
- VERSION = "2.3.2"
2
+ VERSION = "2.4.0"
3
3
  end
4
4
 
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ describe "aliases and overrides" do
4
+ before do
5
+ Factory.alias /one/, "two"
6
+
7
+ define_model("User", :two => :string, :one => :string)
8
+
9
+ FactoryGirl.define do
10
+ factory :user do
11
+ two "set value"
12
+ end
13
+ end
14
+ end
15
+
16
+ subject { FactoryGirl.create(:user, :one => "override") }
17
+ its(:one) { should == "override" }
18
+ its(:two) { should be_nil }
19
+ end
@@ -40,7 +40,8 @@ describe "a generated attributes hash" do
40
40
  end
41
41
 
42
42
  it "doesn't assign associations" do
43
- subject[:user_id].should be_nil
43
+ subject.should_not have_key(:user_id)
44
+ subject.should_not have_key(:user)
44
45
  end
45
46
  end
46
47
 
@@ -60,6 +61,14 @@ describe "calling `attributes_for` with a block" do
60
61
  attributes[:name].should eq('thoughtbot')
61
62
  end
62
63
  end
64
+
65
+ it "returns the hash of attributes" do
66
+ expected = nil
67
+ attributes_for(:company) do |attributes|
68
+ expected = attributes
69
+ "hello!"
70
+ end.should == expected
71
+ end
63
72
  end
64
73
 
65
74
  describe "`attributes_for` for a class whose constructor has required params" do
@@ -0,0 +1,53 @@
1
+ require "spec_helper"
2
+
3
+ describe "calling methods on the model instance" do
4
+ before do
5
+ define_model('User', :age => :integer, :age_copy => :integer) do
6
+ def age
7
+ read_attribute(:age) || 18
8
+ end
9
+ end
10
+
11
+ FactoryGirl.define do
12
+ factory :user do
13
+ age_copy { age }
14
+ end
15
+ end
16
+ end
17
+
18
+ context "without the attribute being overridden" do
19
+ it "returns the correct value from the instance" do
20
+ FactoryGirl.build(:user).age_copy.should == 18
21
+ end
22
+
23
+ it "returns nil during attributes_for" do
24
+ FactoryGirl.attributes_for(:user)[:age_copy].should be_nil
25
+ end
26
+
27
+ it "doesn't instantiate a record with attributes_for" do
28
+ User.stubs(:new)
29
+ FactoryGirl.attributes_for(:user)
30
+ User.should have_received(:new).never
31
+ end
32
+ end
33
+
34
+ context "with the attribute being overridden" do
35
+ it "uses the overridden value" do
36
+ FactoryGirl.build(:user, :age_copy => nil).age_copy.should be_nil
37
+ end
38
+
39
+ it "uses the overridden value during attributes_for" do
40
+ FactoryGirl.attributes_for(:user, :age_copy => 25)[:age_copy].should == 25
41
+ end
42
+ end
43
+
44
+ context "with the referenced attribute being overridden" do
45
+ it "uses the overridden value" do
46
+ FactoryGirl.build(:user, :age => nil).age_copy.should be_nil
47
+ end
48
+
49
+ it "uses the overridden value during attributes_for" do
50
+ FactoryGirl.attributes_for(:user, :age => 25)[:age_copy].should == 25
51
+ end
52
+ end
53
+ end
@@ -78,4 +78,12 @@ describe "calling `build` with a block" do
78
78
  company.name.should eq('thoughtbot')
79
79
  end
80
80
  end
81
+
82
+ it "returns the built instance" do
83
+ expected = nil
84
+ build(:company) do |company|
85
+ expected = company
86
+ "hello!"
87
+ end.should == expected
88
+ end
81
89
  end
@@ -8,6 +8,7 @@ describe "a generated stub instance" do
8
8
 
9
9
  define_model('Post', :title => :string,
10
10
  :body => :string,
11
+ :age => :integer,
11
12
  :user_id => :integer) do
12
13
  belongs_to :user
13
14
  end
@@ -92,4 +93,12 @@ describe "calling `build_stubbed` with a block" do
92
93
  expect { company.save }.to raise_error(RuntimeError)
93
94
  end
94
95
  end
96
+
97
+ it "returns the stub instance" do
98
+ expected = nil
99
+ build_stubbed(:company) do |company|
100
+ expected = company
101
+ "hello!"
102
+ end.should == expected
103
+ end
95
104
  end
@@ -106,4 +106,12 @@ describe "calling `create` with a block" do
106
106
  company.name.should eq('thoughtbot')
107
107
  end
108
108
  end
109
+
110
+ it "returns the created instance" do
111
+ expected = nil
112
+ create(:company) do |company|
113
+ expected = company
114
+ "hello!"
115
+ end.should == expected
116
+ end
109
117
  end
@@ -7,18 +7,19 @@ describe FactoryGirl::Attribute::Association do
7
7
  let(:association) { stub("association") }
8
8
  let(:proxy) { stub("proxy", :association => association) }
9
9
 
10
- subject { FactoryGirl::Attribute::Association.new(name, factory, overrides) }
10
+ subject { FactoryGirl::Attribute::Association.new(name, factory, overrides) }
11
+ before { subject.stubs(:association => association) }
11
12
 
12
13
  it { should be_association }
13
14
  its(:name) { should == name }
14
15
 
15
16
  it "builds the association when calling the proc" do
16
- subject.to_proc(proxy).call.should == association
17
+ subject.to_proc.call.should == association
17
18
  end
18
19
 
19
20
  it "builds the association when calling the proc" do
20
- subject.to_proc(proxy).call
21
- proxy.should have_received(:association).with(factory, overrides)
21
+ subject.to_proc.call
22
+ subject.should have_received(:association).with(factory, overrides)
22
23
  end
23
24
  end
24
25
 
@@ -2,7 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  describe FactoryGirl::Attribute::Dynamic do
4
4
  let(:name) { :first_name }
5
- let(:proxy) { stub("proxy", :set => nil) }
6
5
  let(:block) { lambda { } }
7
6
 
8
7
  subject { FactoryGirl::Attribute::Dynamic.new(name, false, block) }
@@ -13,28 +12,28 @@ describe FactoryGirl::Attribute::Dynamic do
13
12
  let(:block) { lambda { "value" } }
14
13
 
15
14
  it "returns the value when executing the proc" do
16
- subject.to_proc(proxy).call.should == "value"
15
+ subject.to_proc.call.should == "value"
17
16
  end
18
17
  end
19
18
 
20
19
  context "with a block returning its block-level variable" do
21
20
  let(:block) { lambda {|thing| thing } }
22
21
 
23
- it "returns the proxy when executing the proc" do
24
- subject.to_proc(proxy).call.should == proxy
22
+ it "returns self when executing the proc" do
23
+ subject.to_proc.call.should == subject
25
24
  end
26
25
  end
27
26
 
28
- context "with a block referencing an attribute on the proxy" do
29
- let(:block) { lambda { attribute_defined_on_proxy } }
27
+ context "with a block referencing an attribute on the attribute" do
28
+ let(:block) { lambda { attribute_defined_on_attribute } }
30
29
  let(:result) { "other attribute value" }
31
30
 
32
31
  before do
33
- proxy.stubs(:attribute_defined_on_proxy => result)
32
+ subject.stubs(:attribute_defined_on_attribute => result)
34
33
  end
35
34
 
36
- it "evaluates the attribute from the proxy" do
37
- subject.to_proc(proxy).call.should == result
35
+ it "evaluates the attribute from the attribute" do
36
+ subject.to_proc.call.should == result
38
37
  end
39
38
  end
40
39
 
@@ -42,7 +41,7 @@ describe FactoryGirl::Attribute::Dynamic do
42
41
  let(:block) { lambda { Factory.sequence(:email) } }
43
42
 
44
43
  it "raises a sequence abuse error" do
45
- expect { subject.to_proc(proxy).call }.to raise_error(FactoryGirl::SequenceAbuseError)
44
+ expect { subject.to_proc.call }.to raise_error(FactoryGirl::SequenceAbuseError)
46
45
  end
47
46
  end
48
47
  end
@@ -4,7 +4,6 @@ describe FactoryGirl::Attribute::Sequence do
4
4
  let(:sequence_name) { :name }
5
5
  let(:name) { :first_name }
6
6
  let(:sequence) { FactoryGirl::Sequence.new(sequence_name, 5) { |n| "Name #{n}" } }
7
- let(:proxy) { stub("proxy") }
8
7
 
9
8
  subject { FactoryGirl::Attribute::Sequence.new(name, sequence_name, false) }
10
9
  before { FactoryGirl.register_sequence(sequence) }
@@ -12,6 +11,6 @@ describe FactoryGirl::Attribute::Sequence do
12
11
  its(:name) { should == name }
13
12
 
14
13
  it "assigns the next value in the sequence" do
15
- subject.to_proc(proxy).call.should == "Name 5"
14
+ subject.to_proc.call.should == "Name 5"
16
15
  end
17
16
  end
@@ -3,14 +3,13 @@ require 'spec_helper'
3
3
  describe FactoryGirl::Attribute::Static do
4
4
  let(:name) { :first_name }
5
5
  let(:value) { "John" }
6
- let(:proxy) { stub("proxy") }
7
6
 
8
7
  subject { FactoryGirl::Attribute::Static.new(name, value, false) }
9
8
 
10
9
  its(:name) { should == name }
11
10
 
12
11
  it "returns the value when executing the proc" do
13
- subject.to_proc(proxy).call.should == value
12
+ subject.to_proc.call.should == value
14
13
  end
15
14
  end
16
15
 
@@ -57,12 +57,22 @@ describe FactoryGirl::AttributeList, "#apply_attributes" do
57
57
  subject.apply_attributes(list(city_attribute, email_attribute))
58
58
  subject.to_a.should == [full_name_attribute, login_attribute, city_attribute, email_attribute]
59
59
  end
60
+ end
61
+
62
+ describe FactoryGirl::AttributeList, "#associations" do
63
+ let(:full_name_attribute) { FactoryGirl::Attribute::Static.new(:full_name, "value", false) }
64
+ let(:email_attribute) { FactoryGirl::Attribute::Dynamic.new(:email, false, lambda {|u| "#{u.full_name}@example.com" }) }
65
+ let(:author_attribute) { FactoryGirl::Attribute::Association.new(:author, :user, {}) }
66
+ let(:profile_attribute) { FactoryGirl::Attribute::Association.new(:profile, :profile, {}) }
60
67
 
61
- it "doesn't overwrite attributes that are already defined" do
68
+ before do
62
69
  subject.define_attribute(full_name_attribute)
63
- attribute_with_same_name = FactoryGirl::Attribute::Static.new(:full_name, "Benjamin Franklin", false)
70
+ subject.define_attribute(email_attribute)
71
+ subject.define_attribute(author_attribute)
72
+ subject.define_attribute(profile_attribute)
73
+ end
64
74
 
65
- subject.apply_attributes(list(attribute_with_same_name))
66
- subject.to_a.should == [full_name_attribute]
75
+ it "returns associations" do
76
+ subject.associations.should == [author_attribute, profile_attribute]
67
77
  end
68
78
  end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+
3
+ describe FactoryGirl::EvaluatorClassDefiner do
4
+ let(:simple_attribute) { stub("simple attribute", :name => :simple, :to_proc => lambda { 1 }) }
5
+ let(:relative_attribute) { stub("relative attribute", :name => :relative, :to_proc => lambda { simple + 1 }) }
6
+ let(:attribute_that_raises_a_second_time) { stub("attribute that would raise without a cache", :name => :raises_without_proper_cache, :to_proc => lambda { raise "failed" if @run; @run = true; nil }) }
7
+ let(:callbacks) { [stub("callback 1"), stub("callback 2")] }
8
+
9
+ let(:attributes) { [simple_attribute, relative_attribute, attribute_that_raises_a_second_time] }
10
+ let(:class_definer) { FactoryGirl::EvaluatorClassDefiner.new(attributes, callbacks, FactoryGirl::Evaluator) }
11
+ let(:evaluator) { class_definer.evaluator_class.new(stub("build strategy", :add_observer => true)) }
12
+
13
+ it "returns an evaluator when accessing the evaluator class" do
14
+ evaluator.should be_a(FactoryGirl::Evaluator)
15
+ end
16
+
17
+ it "adds each attribute to the evaluator" do
18
+ evaluator.simple.should == 1
19
+ end
20
+
21
+ it "evaluates the block in the context of the evaluator" do
22
+ evaluator.relative.should == 2
23
+ end
24
+
25
+ it "only instance_execs the block once even when returning nil" do
26
+ expect {
27
+ 2.times { evaluator.raises_without_proper_cache }
28
+ }.to_not raise_error
29
+ end
30
+
31
+ it "sets attributes on the evaluator class" do
32
+ class_definer.evaluator_class.attribute_lists.should == [attributes]
33
+ end
34
+
35
+ it "sets callbacks on the evaluator class" do
36
+ class_definer.evaluator_class.callbacks.should == callbacks
37
+ end
38
+
39
+ context "with a custom evaluator as a parent class" do
40
+ let(:child_callbacks) { [stub("child callback 1"), stub("child callback 2")] }
41
+ let(:child_attributes) { [stub("child attribute", :name => :simple, :to_proc => lambda { 1 })] }
42
+ let(:child_definer) { FactoryGirl::EvaluatorClassDefiner.new(child_attributes, child_callbacks, class_definer.evaluator_class) }
43
+
44
+ subject { child_definer.evaluator_class }
45
+
46
+ it "bases its attribute lists on itself and its parent evaluator" do
47
+ subject.attribute_lists.should == [attributes, child_attributes]
48
+ end
49
+
50
+ it "bases its callbacks on itself and its parent evaluator" do
51
+ subject.callbacks.should == callbacks + child_callbacks
52
+ end
53
+ end
54
+ end
@@ -25,7 +25,7 @@ describe FactoryGirl::Factory do
25
25
  end
26
26
 
27
27
  it "passes a custom creation block" do
28
- proxy = stub("proxy", :result => nil)
28
+ proxy = stub("proxy", :result => nil, :add_observer => true)
29
29
  FactoryGirl::Proxy::Build.stubs(:new => proxy)
30
30
  block = lambda {}
31
31
  factory = FactoryGirl::Factory.new(:object)
@@ -33,7 +33,7 @@ describe FactoryGirl::Factory do
33
33
 
34
34
  factory.run(FactoryGirl::Proxy::Build, {})
35
35
 
36
- proxy.should have_received(:result).with(block)
36
+ proxy.should have_received(:result).with(instance_of(FactoryGirl::AttributeAssigner), block)
37
37
  end
38
38
 
39
39
  it "returns associations" do
@@ -116,6 +116,25 @@ describe FactoryGirl::Factory, "when defined with a custom class" do
116
116
  its(:build_class) { should == Float }
117
117
  end
118
118
 
119
+ describe FactoryGirl::Factory, "when given a class that overrides #to_s" do
120
+ let(:overriding_class) { Overriding::Class }
121
+
122
+ before do
123
+ define_class("Overriding")
124
+ define_class("Overriding::Class") do
125
+ def self.to_s
126
+ "Overriding"
127
+ end
128
+ end
129
+ end
130
+
131
+ subject { FactoryGirl::Factory.new(:overriding_class, :class => Overriding::Class) }
132
+
133
+ it "sets build_class correctly" do
134
+ subject.build_class.should == overriding_class
135
+ end
136
+ end
137
+
119
138
  describe FactoryGirl::Factory, "when defined with a class instead of a name" do
120
139
  let(:factory_class) { ArgumentError }
121
140
  let(:name) { :argument_error }
@@ -246,7 +265,7 @@ describe FactoryGirl::Factory, "running a factory" do
246
265
  subject { FactoryGirl::Factory.new(:user) }
247
266
  let(:attribute) { FactoryGirl::Attribute::Static.new(:name, "value", false) }
248
267
  let(:declaration) { FactoryGirl::Declaration::Static.new(:name, "value", false) }
249
- let(:proxy) { stub("proxy", :result => "result", :set => nil) }
268
+ let(:proxy) { stub("proxy", :result => "result", :add_observer => true) }
250
269
  let(:attributes) { [attribute] }
251
270
  let(:attribute_list) { stub('attribute-list', :declarations => [declaration], :to_a => attributes) }
252
271
 
@@ -254,29 +273,17 @@ describe FactoryGirl::Factory, "running a factory" do
254
273
  define_model("User", :name => :string)
255
274
  FactoryGirl::Declaration::Static.stubs(:new => declaration)
256
275
  declaration.stubs(:to_attributes => attributes)
257
- attribute.stubs(:add_to => nil)
258
276
  FactoryGirl::Proxy::Build.stubs(:new => proxy)
259
277
  subject.declare_attribute(declaration)
260
278
  end
261
279
 
262
280
  it "creates the right proxy using the build class when running" do
263
281
  subject.run(FactoryGirl::Proxy::Build, {})
264
- FactoryGirl::Proxy::Build.should have_received(:new).with(subject.build_class, [])
265
- end
266
-
267
- it "adds the attribute to the proxy when running" do
268
- subject.run(FactoryGirl::Proxy::Build, {})
269
- attribute.should have_received(:add_to).with(proxy)
282
+ FactoryGirl::Proxy::Build.should have_received(:new).once
270
283
  end
271
284
 
272
285
  it "returns the result from the proxy when running" do
273
286
  subject.run(FactoryGirl::Proxy::Build, {}).should == "result"
274
- proxy.should have_received(:result).with(subject.definition.to_create)
275
- end
276
-
277
- it "sets overrides once on the factory" do
278
- subject.run(FactoryGirl::Proxy::Build, { :name => "John Doe" })
279
- proxy.should have_received(:set).once
280
287
  end
281
288
 
282
289
  it "calls the block and returns the result" do