factory_girl 2.3.2 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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