factory_girl 1.3.3 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/README.rdoc +68 -60
  2. data/features/support/test.db +0 -0
  3. data/lib/factory_girl.rb +6 -12
  4. data/lib/factory_girl/aliases.rb +2 -31
  5. data/lib/factory_girl/attribute.rb +1 -1
  6. data/lib/factory_girl/attribute/association.rb +1 -1
  7. data/lib/factory_girl/attribute/callback.rb +1 -1
  8. data/lib/factory_girl/attribute/dynamic.rb +3 -3
  9. data/lib/factory_girl/attribute/static.rb +1 -1
  10. data/lib/factory_girl/definition_proxy.rb +180 -0
  11. data/lib/factory_girl/deprecated.rb +18 -0
  12. data/lib/factory_girl/factory.rb +120 -355
  13. data/lib/factory_girl/find_definitions.rb +25 -0
  14. data/lib/factory_girl/proxy.rb +4 -6
  15. data/lib/factory_girl/proxy/attributes_for.rb +1 -1
  16. data/lib/factory_girl/proxy/build.rb +7 -5
  17. data/lib/factory_girl/proxy/create.rb +1 -1
  18. data/lib/factory_girl/proxy/stub.rb +11 -5
  19. data/lib/factory_girl/rails2.rb +1 -1
  20. data/lib/factory_girl/sequence.rb +5 -40
  21. data/lib/factory_girl/step_definitions.rb +7 -7
  22. data/lib/factory_girl/syntax.rb +7 -7
  23. data/lib/factory_girl/syntax/blueprint.rb +5 -4
  24. data/lib/factory_girl/syntax/default.rb +31 -0
  25. data/lib/factory_girl/syntax/generate.rb +13 -8
  26. data/lib/factory_girl/syntax/make.rb +8 -6
  27. data/lib/factory_girl/syntax/sham.rb +11 -8
  28. data/lib/factory_girl/syntax/vintage.rb +196 -0
  29. data/lib/factory_girl/version.rb +4 -0
  30. data/spec/acceptance/acceptance_spec.rb +43 -60
  31. data/spec/acceptance/syntax/blueprint_spec.rb +1 -5
  32. data/spec/acceptance/syntax/generate_spec.rb +1 -4
  33. data/spec/acceptance/syntax/make_spec.rb +1 -4
  34. data/spec/acceptance/syntax/sham_spec.rb +9 -7
  35. data/spec/acceptance/syntax/vintage_spec.rb +184 -0
  36. data/spec/factory_girl/aliases_spec.rb +5 -5
  37. data/spec/factory_girl/attribute/association_spec.rb +3 -3
  38. data/spec/factory_girl/attribute/callback_spec.rb +3 -3
  39. data/spec/factory_girl/attribute/dynamic_spec.rb +20 -9
  40. data/spec/factory_girl/attribute/static_spec.rb +5 -5
  41. data/spec/factory_girl/attribute_spec.rb +5 -5
  42. data/spec/factory_girl/definition_proxy_spec.rb +138 -0
  43. data/spec/factory_girl/deprecated_spec.rb +66 -0
  44. data/spec/factory_girl/factory_spec.rb +283 -566
  45. data/spec/factory_girl/find_definitions_spec.rb +89 -0
  46. data/spec/factory_girl/proxy/attributes_for_spec.rb +2 -2
  47. data/spec/factory_girl/proxy/build_spec.rb +17 -12
  48. data/spec/factory_girl/proxy/create_spec.rb +17 -12
  49. data/spec/factory_girl/proxy/stub_spec.rb +6 -5
  50. data/spec/factory_girl/proxy_spec.rb +2 -2
  51. data/spec/factory_girl/sequence_spec.rb +15 -38
  52. data/spec/spec_helper.rb +4 -0
  53. metadata +28 -11
@@ -0,0 +1,196 @@
1
+ module FactoryGirl
2
+ module Syntax
3
+ module Vintage
4
+ module Factory
5
+ # Defines a new factory that can be used by the build strategies (create and
6
+ # build) to build new objects.
7
+ #
8
+ # Arguments:
9
+ # * name: +Symbol+ or +String+
10
+ # A unique name used to identify this factory.
11
+ # * options: +Hash+
12
+ #
13
+ # Options:
14
+ # * class: +Symbol+, +Class+, or +String+
15
+ # The class that will be used when generating instances for this factory. If not specified, the class will be guessed from the factory name.
16
+ # * parent: +Symbol+
17
+ # The parent factory. If specified, the attributes from the parent
18
+ # factory will be copied to the current one with an ability to override
19
+ # them.
20
+ # * default_strategy: +Symbol+
21
+ # The strategy that will be used by the Factory shortcut method.
22
+ # Defaults to :create.
23
+ #
24
+ # Yields: +Factory+
25
+ # The newly created factory.
26
+ def self.define(name, options = {})
27
+ factory = FactoryGirl::Factory.new(name, options)
28
+ proxy = FactoryGirl::DefinitionProxy.new(factory)
29
+ yield(proxy)
30
+ if parent = options.delete(:parent)
31
+ factory.inherit_from(FactoryGirl.factory_by_name(parent))
32
+ end
33
+ FactoryGirl.register_factory(factory)
34
+ end
35
+
36
+ # Generates and returns a Hash of attributes from this factory. Attributes
37
+ # can be individually overridden by passing in a Hash of attribute => value
38
+ # pairs.
39
+ #
40
+ # Arguments:
41
+ # * name: +Symbol+ or +String+
42
+ # The name of the factory that should be used.
43
+ # * overrides: +Hash+
44
+ # Attributes to overwrite for this set.
45
+ #
46
+ # Returns: +Hash+
47
+ # A set of attributes that can be used to build an instance of the class
48
+ # this factory generates.
49
+ def self.attributes_for(name, overrides = {})
50
+ FactoryGirl.factory_by_name(name).run(Proxy::AttributesFor, overrides)
51
+ end
52
+
53
+ # Generates and returns an instance from this factory. Attributes can be
54
+ # individually overridden by passing in a Hash of attribute => value pairs.
55
+ #
56
+ # Arguments:
57
+ # * name: +Symbol+ or +String+
58
+ # The name of the factory that should be used.
59
+ # * overrides: +Hash+
60
+ # Attributes to overwrite for this instance.
61
+ #
62
+ # Returns: +Object+
63
+ # An instance of the class this factory generates, with generated attributes
64
+ # assigned.
65
+ def self.build(name, overrides = {})
66
+ FactoryGirl.factory_by_name(name).run(Proxy::Build, overrides)
67
+ end
68
+
69
+ # Generates, saves, and returns an instance from this factory. Attributes can
70
+ # be individually overridden by passing in a Hash of attribute => value
71
+ # pairs.
72
+ #
73
+ # Instances are saved using the +save!+ method, so ActiveRecord models will
74
+ # raise ActiveRecord::RecordInvalid exceptions for invalid attribute sets.
75
+ #
76
+ # Arguments:
77
+ # * name: +Symbol+ or +String+
78
+ # The name of the factory that should be used.
79
+ # * overrides: +Hash+
80
+ # Attributes to overwrite for this instance.
81
+ #
82
+ # Returns: +Object+
83
+ # A saved instance of the class this factory generates, with generated
84
+ # attributes assigned.
85
+ def self.create(name, overrides = {})
86
+ FactoryGirl.factory_by_name(name).run(Proxy::Create, overrides)
87
+ end
88
+
89
+ # Generates and returns an object with all attributes from this factory
90
+ # stubbed out. Attributes can be individually overridden by passing in a Hash
91
+ # of attribute => value pairs.
92
+ #
93
+ # Arguments:
94
+ # * name: +Symbol+ or +String+
95
+ # The name of the factory that should be used.
96
+ # * overrides: +Hash+
97
+ # Attributes to overwrite for this instance.
98
+ #
99
+ # Returns: +Object+
100
+ # An object with generated attributes stubbed out.
101
+ def self.stub(name, overrides = {})
102
+ FactoryGirl.factory_by_name(name).run(Proxy::Stub, overrides)
103
+ end
104
+
105
+ # Executes the default strategy for the given factory. This is usually create,
106
+ # but it can be overridden for each factory.
107
+ #
108
+ # Arguments:
109
+ # * name: +Symbol+ or +String+
110
+ # The name of the factory that should be used.
111
+ # * overrides: +Hash+
112
+ # Attributes to overwrite for this instance.
113
+ #
114
+ # Returns: +Object+
115
+ # The result of the default strategy.
116
+ def self.default_strategy(name, overrides = {})
117
+ self.send(FactoryGirl.factory_by_name(name).default_strategy, name, overrides)
118
+ end
119
+
120
+ # Defines a new sequence that can be used to generate unique values in a specific format.
121
+ #
122
+ # Arguments:
123
+ # name: (Symbol)
124
+ # A unique name for this sequence. This name will be referenced when
125
+ # calling next to generate new values from this sequence.
126
+ # block: (Proc)
127
+ # The code to generate each value in the sequence. This block will be
128
+ # called with a unique number each time a value in the sequence is to be
129
+ # generated. The block should return the generated value for the
130
+ # sequence.
131
+ #
132
+ # Example:
133
+ #
134
+ # Factory.sequence(:email) {|n| "somebody_#{n}@example.com" }
135
+ def self.sequence(name, start_value = 1, &block)
136
+ FactoryGirl.sequences[name] = Sequence.new(start_value, &block)
137
+ end
138
+
139
+ # Generates and returns the next value in a sequence.
140
+ #
141
+ # Arguments:
142
+ # name: (Symbol)
143
+ # The name of the sequence that a value should be generated for.
144
+ #
145
+ # Returns:
146
+ # The next value in the sequence. (Object)
147
+ def self.next(sequence)
148
+ unless FactoryGirl.sequences.key?(sequence)
149
+ raise "No such sequence: #{sequence}"
150
+ end
151
+
152
+ FactoryGirl.sequences[sequence].next
153
+ end
154
+
155
+ # Defines a new alias for attributes.
156
+ #
157
+ # Arguments:
158
+ # * pattern: +Regexp+
159
+ # A pattern that will be matched against attributes when looking for
160
+ # aliases. Contents captured in the pattern can be used in the alias.
161
+ # * replace: +String+
162
+ # The alias that results from the matched pattern. Captured strings can
163
+ # be substituted like with +String#sub+.
164
+ #
165
+ # Example:
166
+ #
167
+ # Factory.alias /(.*)_confirmation/, '\1'
168
+ #
169
+ # factory_girl starts with aliases for foreign keys, so that a :user
170
+ # association can be overridden by a :user_id parameter:
171
+ #
172
+ # Factory.define :post do |p|
173
+ # p.association :user
174
+ # end
175
+ #
176
+ # # The user association will not be built in this example. The user_id
177
+ # # will be used instead.
178
+ # Factory(:post, :user_id => 1)
179
+ def self.alias(pattern, replace)
180
+ FactoryGirl.aliases << [pattern, replace]
181
+ end
182
+
183
+ end
184
+
185
+ # Shortcut for Factory.default_strategy.
186
+ #
187
+ # Example:
188
+ # Factory(:user, :name => 'Joe')
189
+ def Factory(name, attrs = {})
190
+ Factory.default_strategy(name, attrs)
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ include FactoryGirl::Syntax::Vintage
@@ -0,0 +1,4 @@
1
+ module FactoryGirl
2
+ VERSION = "2.0.0.beta1"
3
+ end
4
+
@@ -3,61 +3,60 @@ require 'acceptance/acceptance_helper'
3
3
 
4
4
  describe "integration" do
5
5
  before do
6
- Factory.define :user, :class => 'user' do |f|
7
- f.first_name 'Jimi'
8
- f.last_name 'Hendrix'
9
- f.admin false
10
- f.email {|a| "#{a.first_name}.#{a.last_name}@example.com".downcase }
11
- end
6
+ FactoryGirl.define do
7
+ sequence :email do |n|
8
+ "somebody#{n}@example.com"
9
+ end
12
10
 
13
- Factory.define Post, :default_strategy => :attributes_for do |f|
14
- f.name 'Test Post'
15
- f.association :author, :factory => :user
16
- end
11
+ factory :user, :class => 'user' do
12
+ first_name 'Jimi'
13
+ last_name 'Hendrix'
14
+ admin false
15
+ email { "#{first_name}.#{last_name}@example.com".downcase }
17
16
 
18
- Factory.define :admin, :class => User do |f|
19
- f.first_name 'Ben'
20
- f.last_name 'Stein'
21
- f.admin true
22
- f.sequence(:username) { |n| "username#{n}" }
23
- f.email { Factory.next(:email) }
24
- end
17
+ aliased_as :author
18
+ end
25
19
 
26
- Factory.define :sequence_abuser, :class => User do |f|
27
- f.first_name { Factory.sequence(:email) }
28
- end
20
+ factory Post, :default_strategy => :attributes_for do
21
+ name 'Test Post'
22
+ author
23
+ end
29
24
 
30
- Factory.define :guest, :parent => :user do |f|
31
- f.last_name 'Anonymous'
32
- f.username 'GuestUser'
33
- end
25
+ factory :admin, :class => User do
26
+ first_name 'Ben'
27
+ last_name 'Stein'
28
+ admin true
29
+ sequence(:username) { |n| "username#{n}" }
30
+ email
31
+ end
34
32
 
35
- Factory.define :user_with_callbacks, :parent => :user do |f|
36
- f.after_stub {|u| u.first_name = 'Stubby' }
37
- f.after_build {|u| u.first_name = 'Buildy' }
38
- f.after_create {|u| u.last_name = 'Createy' }
39
- end
33
+ factory :sequence_abuser, :class => User do
34
+ first_name { Factory.sequence(:email) }
35
+ end
40
36
 
41
- Factory.define :user_with_inherited_callbacks, :parent => :user_with_callbacks do |f|
42
- f.callback(:after_stub) {|u| u.last_name = 'Double-Stubby' }
43
- end
37
+ factory :guest, :parent => :user do
38
+ last_name 'Anonymous'
39
+ username 'GuestUser'
40
+ end
44
41
 
45
- Factory.define :business do |f|
46
- f.name 'Supplier of Awesome'
47
- f.association :owner, :factory => :user
48
- end
42
+ factory :user_with_callbacks, :parent => :user do
43
+ after_stub {|u| u.first_name = 'Stubby' }
44
+ after_build {|u| u.first_name = 'Buildy' }
45
+ after_create {|u| u.last_name = 'Createy' }
46
+ end
49
47
 
50
- Factory.sequence :email do |n|
51
- "somebody#{n}@example.com"
52
- end
53
- end
48
+ factory :user_with_inherited_callbacks, :parent => :user_with_callbacks do
49
+ after_stub {|u| u.last_name = 'Double-Stubby' }
50
+ end
54
51
 
55
- after do
56
- Factory.factories.clear
52
+ factory :business do
53
+ name 'Supplier of Awesome'
54
+ association :owner, :factory => :user
55
+ end
56
+ end
57
57
  end
58
58
 
59
59
  describe "a generated attributes hash" do
60
-
61
60
  before do
62
61
  @attrs = Factory.attributes_for(:user, :first_name => 'Bill')
63
62
  end
@@ -79,11 +78,9 @@ describe "integration" do
79
78
  it "should not assign associations" do
80
79
  Factory.attributes_for(:post)[:author].should be_nil
81
80
  end
82
-
83
81
  end
84
82
 
85
83
  describe "a built instance" do
86
-
87
84
  before do
88
85
  @instance = Factory.build(:post)
89
86
  end
@@ -103,11 +100,9 @@ describe "integration" do
103
100
  it "should not assign both an association and its foreign key" do
104
101
  Factory.build(:post, :author_id => 1).author_id.should == 1
105
102
  end
106
-
107
103
  end
108
104
 
109
105
  describe "a created instance" do
110
-
111
106
  before do
112
107
  @instance = Factory.create('post')
113
108
  end
@@ -123,11 +118,9 @@ describe "integration" do
123
118
  it "should save associations" do
124
119
  @instance.author.should_not be_new_record
125
120
  end
126
-
127
121
  end
128
122
 
129
123
  describe "a generated stub instance" do
130
-
131
124
  before do
132
125
  @stub = Factory.stub(:user, :first_name => 'Bill')
133
126
  end
@@ -174,7 +167,6 @@ describe "integration" do
174
167
  end
175
168
 
176
169
  describe "an instance generated by a factory with a custom class name" do
177
-
178
170
  before do
179
171
  @instance = Factory.create(:admin)
180
172
  end
@@ -186,7 +178,6 @@ describe "integration" do
186
178
  it "should use the correct factory definition" do
187
179
  @instance.should be_admin
188
180
  end
189
-
190
181
  end
191
182
 
192
183
  describe "an instance generated by a factory that inherits from another factory" do
@@ -212,7 +203,6 @@ describe "integration" do
212
203
  end
213
204
 
214
205
  describe "an attribute generated by a sequence" do
215
-
216
206
  before do
217
207
  @email = Factory.attributes_for(:admin)[:email]
218
208
  end
@@ -222,7 +212,6 @@ describe "integration" do
222
212
  end
223
213
 
224
214
  describe "after the attribute has already been generated once" do
225
-
226
215
  before do
227
216
  @another_email = Factory.attributes_for(:admin)[:email]
228
217
  end
@@ -234,13 +223,10 @@ describe "integration" do
234
223
  it "should not be the same as the first generated value" do
235
224
  @another_email.should_not == @email
236
225
  end
237
-
238
226
  end
239
-
240
227
  end
241
228
 
242
229
  describe "an attribute generated by an in-line sequence" do
243
-
244
230
  before do
245
231
  @username = Factory.attributes_for(:admin)[:username]
246
232
  end
@@ -250,7 +236,6 @@ describe "integration" do
250
236
  end
251
237
 
252
238
  describe "after the attribute has already been generated once" do
253
-
254
239
  before do
255
240
  @another_username = Factory.attributes_for(:admin)[:username]
256
241
  end
@@ -262,9 +247,7 @@ describe "integration" do
262
247
  it "should not be the same as the first generated value" do
263
248
  @another_username.should_not == @username
264
249
  end
265
-
266
250
  end
267
-
268
251
  end
269
252
 
270
253
  describe "a factory with a default strategy specified" do
@@ -276,7 +259,7 @@ describe "integration" do
276
259
  it "should raise Factory::SequenceAbuseError" do
277
260
  lambda {
278
261
  Factory(:sequence_abuser)
279
- }.should raise_error(Factory::SequenceAbuseError)
262
+ }.should raise_error(FactoryGirl::SequenceAbuseError)
280
263
  end
281
264
 
282
265
  describe "an instance with callbacks" do
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'acceptance/acceptance_helper'
2
3
 
3
4
  require 'factory_girl/syntax/blueprint'
4
5
 
@@ -12,11 +13,6 @@ describe "a blueprint" do
12
13
  end
13
14
  end
14
15
 
15
- after do
16
- Factory.factories.clear
17
- Factory.sequences.clear
18
- end
19
-
20
16
  describe "after making an instance" do
21
17
  before do
22
18
  @instance = Factory(:user, :last_name => 'Rye')
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'acceptance/acceptance_helper'
2
3
 
3
4
  require 'factory_girl/syntax/generate'
4
5
 
@@ -11,10 +12,6 @@ describe "a factory using generate syntax" do
11
12
  end
12
13
  end
13
14
 
14
- after do
15
- Factory.factories.clear
16
- end
17
-
18
15
  it "should not raise an error when generating an invalid instance" do
19
16
  lambda { User.generate(:first_name => nil) }.should_not raise_error
20
17
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'acceptance/acceptance_helper'
2
3
 
3
4
  require 'factory_girl/syntax/make'
4
5
 
@@ -11,10 +12,6 @@ describe "a factory using make syntax" do
11
12
  end
12
13
  end
13
14
 
14
- after do
15
- Factory.factories.clear
16
- end
17
-
18
15
  describe "after making an instance" do
19
16
  before do
20
17
  @instance = User.make(:last_name => 'Rye')