gabrielg-factory_girl 1.1.8 → 1.1.9
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/factory_girl/factory.rb +28 -18
- data/test/factory_test.rb +124 -40
- data/test/models.rb +1 -0
- metadata +1 -1
data/lib/factory_girl/factory.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Factory
|
2
|
-
|
2
|
+
|
3
3
|
cattr_accessor :factories #:nodoc:
|
4
4
|
self.factories = {}
|
5
5
|
|
@@ -10,7 +10,7 @@ class Factory
|
|
10
10
|
cattr_accessor :definition_file_paths
|
11
11
|
self.definition_file_paths = %w(factories test/factories spec/factories)
|
12
12
|
|
13
|
-
attr_reader :factory_name
|
13
|
+
attr_reader :factory_name, :inherited_factory
|
14
14
|
|
15
15
|
# Defines a new factory that can be used by the build strategies (create and
|
16
16
|
# build) to build new objects.
|
@@ -20,14 +20,16 @@ class Factory
|
|
20
20
|
# A unique name used to identify this factory.
|
21
21
|
# options: (Hash)
|
22
22
|
# class: the class that will be used when generating instances for this
|
23
|
-
# factory. If not specified, the class will be guessed from the
|
23
|
+
# factory. If not specified, the class will be guessed from the
|
24
24
|
# factory name.
|
25
25
|
#
|
26
26
|
# Yields:
|
27
27
|
# The newly created factory (Factory)
|
28
28
|
def self.define (name, options = {})
|
29
29
|
inherit_from = options.delete(:inherit)
|
30
|
-
|
30
|
+
options = inherit_from ? options.merge(:inherit => factories[inherit_from]) : options
|
31
|
+
raise(ArgumentError, "Inherited factory not defined") if inherit_from && options[:inherit].blank?
|
32
|
+
instance = Factory.new(name, options)
|
31
33
|
yield(instance)
|
32
34
|
self.factories[instance.factory_name] = instance
|
33
35
|
end
|
@@ -37,7 +39,7 @@ class Factory
|
|
37
39
|
end
|
38
40
|
|
39
41
|
def initialize (name, options = {}) #:nodoc:
|
40
|
-
options.assert_valid_keys(:class)
|
42
|
+
options.assert_valid_keys(:class, :inherit)
|
41
43
|
@factory_name = factory_name_for(name)
|
42
44
|
@options = options
|
43
45
|
@attributes = []
|
@@ -45,6 +47,8 @@ class Factory
|
|
45
47
|
@lazy_attribute_blocks = {}
|
46
48
|
@lazy_attribute_names = []
|
47
49
|
@callbacks = {}
|
50
|
+
@inherited_factory = options[:inherit]
|
51
|
+
@options[:class] = inherited_factory.build_class if inherited_factory && !@options.has_key?(:class)
|
48
52
|
end
|
49
53
|
|
50
54
|
# Adds an attribute that should be assigned on generated instances for this
|
@@ -88,7 +92,7 @@ class Factory
|
|
88
92
|
# f.add_attribute :name, 'Billy Idol'
|
89
93
|
# end
|
90
94
|
#
|
91
|
-
# are equivilent.
|
95
|
+
# are equivilent.
|
92
96
|
def method_missing (name, *args, &block)
|
93
97
|
add_attribute(name, *args, &block)
|
94
98
|
end
|
@@ -133,13 +137,16 @@ class Factory
|
|
133
137
|
def create (attrs = {}) #:nodoc:
|
134
138
|
instance, final_attrs = build_instance(attrs, :create)
|
135
139
|
instance.save!
|
136
|
-
|
140
|
+
if callback = @callbacks[:after_create]
|
141
|
+
params = (callback.arity > 1) ? [instance, final_attrs] : [instance]
|
142
|
+
instance_exec(*params, &callback)
|
143
|
+
end
|
137
144
|
instance
|
138
145
|
end
|
139
146
|
|
140
|
-
# Allows a block to be evaluated after the factory object has been built, but before
|
141
|
-
# it is saved to the database. The block is passed the instance so you can do stuff
|
142
|
-
# to it. For example, maybe you want to stub a method whose result normally relies on
|
147
|
+
# Allows a block to be evaluated after the factory object has been built, but before
|
148
|
+
# it is saved to the database. The block is passed the instance so you can do stuff
|
149
|
+
# to it. For example, maybe you want to stub a method whose result normally relies on
|
143
150
|
# complex computation on attributes and associations:
|
144
151
|
#
|
145
152
|
# Factory.define :a_boy_that_never_goes_out, :class => Boy do |f|
|
@@ -152,7 +159,7 @@ class Factory
|
|
152
159
|
@callbacks[:after_build] = block
|
153
160
|
end
|
154
161
|
|
155
|
-
# Allows a block to be evaluated after the factory object has been saved to the
|
162
|
+
# Allows a block to be evaluated after the factory object has been saved to the
|
156
163
|
# database. The block is passed the instance so you can do stuff to it. For example
|
157
164
|
# maybe you want to stub a method whose result normally relies on complex computation
|
158
165
|
# on attributes and associations:
|
@@ -239,13 +246,13 @@ class Factory
|
|
239
246
|
def build_attributes_hash (values, strategy)
|
240
247
|
values = values.symbolize_keys
|
241
248
|
passed_keys = values.keys.collect {|key| Factory.aliases_for(key) }.flatten
|
242
|
-
@attributes.
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
249
|
+
attrs = @attributes.inject(values) do |vals,attribute|
|
250
|
+
next(vals) if passed_keys.include?(attribute.name)
|
251
|
+
proxy = AttributeProxy.new(self, attribute.name, strategy, vals)
|
252
|
+
vals[attribute.name] = attribute.value(proxy)
|
253
|
+
vals
|
247
254
|
end
|
248
|
-
|
255
|
+
inherited_factory ? inherited_factory.attributes_for.merge(attrs) : attrs
|
249
256
|
end
|
250
257
|
|
251
258
|
def build_instance (override, strategy)
|
@@ -254,7 +261,10 @@ class Factory
|
|
254
261
|
attrs.each do |attr, value|
|
255
262
|
instance.send(:"#{attr}=", value) if instance.respond_to?(:"#{attr}=")
|
256
263
|
end
|
257
|
-
|
264
|
+
if callback = @callbacks[:after_build]
|
265
|
+
params = (callback.arity > 1) ? [instance, attrs] : [instance]
|
266
|
+
instance_exec(*params, &callback)
|
267
|
+
end
|
258
268
|
[instance, attrs]
|
259
269
|
end
|
260
270
|
|
data/test/factory_test.rb
CHANGED
@@ -46,13 +46,13 @@ class FactoryTest < Test::Unit::TestCase
|
|
46
46
|
|
47
47
|
should "add the factory to the list of factories" do
|
48
48
|
Factory.define(@name) {|f| }
|
49
|
-
assert_equal Factory.factories[@name],
|
49
|
+
assert_equal Factory.factories[@name],
|
50
50
|
@factory,
|
51
51
|
"Factories: #{Factory.factories.inspect}"
|
52
52
|
end
|
53
53
|
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
context "a factory" do
|
57
57
|
|
58
58
|
setup do
|
@@ -68,7 +68,7 @@ class FactoryTest < Test::Unit::TestCase
|
|
68
68
|
should "have a build class" do
|
69
69
|
assert_equal @class, @factory.build_class
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
should "have a set of callbacks" do
|
73
73
|
assert @factory.instance_eval {@callbacks}
|
74
74
|
end
|
@@ -77,6 +77,62 @@ class FactoryTest < Test::Unit::TestCase
|
|
77
77
|
assert @factory.instance_eval {@callbacks.empty?}
|
78
78
|
end
|
79
79
|
|
80
|
+
context "when inheriting from a prior factory" do
|
81
|
+
setup do
|
82
|
+
@factory.foo "bar"
|
83
|
+
@factory.snafu "foo"
|
84
|
+
@new_factory = Factory.new(:user_with_stuff, :inherit => @factory)
|
85
|
+
@new_factory.foo "fighters"
|
86
|
+
@instance = @new_factory.build
|
87
|
+
end
|
88
|
+
|
89
|
+
should "use subfactory's class if not specified" do
|
90
|
+
assert_equal User, @factory.build_class
|
91
|
+
end
|
92
|
+
|
93
|
+
should "allow overriding subfactory's class" do
|
94
|
+
newer_factory = Factory.new(:user_with_more_stuff, :inherit => @new_factory, :class => Post)
|
95
|
+
assert_equal Post, newer_factory.build_class
|
96
|
+
end
|
97
|
+
|
98
|
+
should "override previously configured attributes" do
|
99
|
+
assert_equal "fighters", @instance.foo
|
100
|
+
end
|
101
|
+
|
102
|
+
should "inherit attributes that arent overridden" do
|
103
|
+
assert_equal "foo", @instance.snafu
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
context "when defining an inheriting factory" do
|
109
|
+
setup do
|
110
|
+
@original_user_with_stuff_factory = Factory.factories[:user_with_stuff]
|
111
|
+
end
|
112
|
+
|
113
|
+
teardown do
|
114
|
+
Factory.factories[:user_with_stuff] = @original_user_with_stuff_factory
|
115
|
+
end
|
116
|
+
|
117
|
+
should "pass in an instance of the inherited factory as the inherited_factory" do
|
118
|
+
assert_not_nil Factory.factories[:user]
|
119
|
+
instance = Factory.define(:user_with_stuff, :inherit => :user) {}
|
120
|
+
assert_equal Factory.factories[:user], instance.inherited_factory
|
121
|
+
end
|
122
|
+
|
123
|
+
should "get its own factory definition" do
|
124
|
+
instance = Factory.define(:user_with_stuff, :inherit => :user) { }
|
125
|
+
assert_equal instance, Factory.factories[:user_with_stuff]
|
126
|
+
end
|
127
|
+
|
128
|
+
should "raise if inherited factory isnt found" do
|
129
|
+
assert_raise(ArgumentError) do
|
130
|
+
Factory.define(:user_with_stuff, :inherit => :foobar) { }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
80
136
|
context "when adding an after_build callback" do
|
81
137
|
setup do
|
82
138
|
@the_block = lambda{|u| }
|
@@ -86,7 +142,7 @@ class FactoryTest < Test::Unit::TestCase
|
|
86
142
|
should "have something in the set of callbacks" do
|
87
143
|
assert_equal 1, @factory.instance_eval {@callbacks.size}
|
88
144
|
end
|
89
|
-
|
145
|
+
|
90
146
|
should "record the callback in the set of callbacks" do
|
91
147
|
assert @factory.instance_eval {@callbacks.values}.include?(@the_block)
|
92
148
|
end
|
@@ -94,6 +150,7 @@ class FactoryTest < Test::Unit::TestCase
|
|
94
150
|
should "record the callback in the set of callbacks under the after_build key" do
|
95
151
|
assert_equal @the_block, @factory.instance_eval {@callbacks[:after_build]}
|
96
152
|
end
|
153
|
+
|
97
154
|
end
|
98
155
|
|
99
156
|
context "when adding an after_create callback" do
|
@@ -105,7 +162,7 @@ class FactoryTest < Test::Unit::TestCase
|
|
105
162
|
should "have something in the set of callbacks" do
|
106
163
|
assert_equal 1, @factory.instance_eval {@callbacks.size}
|
107
164
|
end
|
108
|
-
|
165
|
+
|
109
166
|
should "record the callback in the set of callbacks" do
|
110
167
|
assert @factory.instance_eval {@callbacks.values}.include?(@the_block)
|
111
168
|
end
|
@@ -177,7 +234,7 @@ class FactoryTest < Test::Unit::TestCase
|
|
177
234
|
end
|
178
235
|
|
179
236
|
context "when other attributes have previously been defined" do
|
180
|
-
|
237
|
+
|
181
238
|
setup do
|
182
239
|
@attr = :unimportant
|
183
240
|
@attrs = {
|
@@ -237,11 +294,11 @@ class FactoryTest < Test::Unit::TestCase
|
|
237
294
|
end
|
238
295
|
|
239
296
|
end
|
240
|
-
|
297
|
+
|
241
298
|
context "specifying an association on a factory with a count" do
|
242
299
|
setup do
|
243
300
|
Factory.define(:post) { |f| f.name "Article" }
|
244
|
-
Factory.define(:user) do |u|
|
301
|
+
Factory.define(:user) do |u|
|
245
302
|
u.first_name "Joe"
|
246
303
|
u.last_name "Bloggs"
|
247
304
|
u.email "joe@example.com"
|
@@ -249,20 +306,20 @@ class FactoryTest < Test::Unit::TestCase
|
|
249
306
|
end
|
250
307
|
@user = Factory(:user)
|
251
308
|
end
|
252
|
-
|
309
|
+
|
253
310
|
should "set up five associated post objects" do
|
254
311
|
assert_equal 5, @user.posts.size
|
255
312
|
end
|
256
|
-
|
313
|
+
|
257
314
|
should "have the user as the author on each object" do
|
258
315
|
@user.posts.each { |p| assert_equal @user, p.author }
|
259
316
|
end
|
260
|
-
|
317
|
+
|
261
318
|
should "have saved all the posts" do
|
262
319
|
@user.posts.each { |p| assert !p.new_record? }
|
263
320
|
end
|
264
|
-
|
265
|
-
end
|
321
|
+
|
322
|
+
end
|
266
323
|
|
267
324
|
should "add an attribute using the method name when passed an undefined method" do
|
268
325
|
@attr = :first_name
|
@@ -380,84 +437,111 @@ class FactoryTest < Test::Unit::TestCase
|
|
380
437
|
end
|
381
438
|
|
382
439
|
context "and an after_build callback has been registered" do
|
440
|
+
saved = nil
|
383
441
|
setup do
|
384
|
-
@the_block = lambda {|user| assert user.new_record?;
|
385
|
-
|
442
|
+
@the_block = lambda {|user| assert user.new_record?; saved = user}
|
443
|
+
|
386
444
|
@factory.after_build &@the_block
|
387
445
|
end
|
388
|
-
|
446
|
+
|
389
447
|
should "call the callback when the object is built" do
|
390
|
-
@
|
448
|
+
@factory.expects(:instance_exec)
|
391
449
|
@factory.build
|
392
450
|
end
|
393
451
|
|
394
452
|
should "call the callback when the object is created" do
|
395
|
-
@
|
453
|
+
@factory.expects(:instance_exec)
|
396
454
|
@factory.create
|
397
455
|
end
|
398
456
|
|
457
|
+
should "yield the instance to block if block arity is <= 1" do
|
458
|
+
@factory.after_build(&(lambda{|user|}))
|
459
|
+
@factory.expects(:instance_exec).with(anything)
|
460
|
+
@factory.build
|
461
|
+
end
|
462
|
+
|
463
|
+
should "yield the instance and attrs to block if block arity is > 1" do
|
464
|
+
@factory.after_build(&(lambda{|user,attrs|}))
|
465
|
+
@factory.expects(:instance_exec).with(anything, instance_of(Hash))
|
466
|
+
@factory.build
|
467
|
+
end
|
468
|
+
|
399
469
|
should "yield the instance to the callback when called" do
|
400
470
|
instance = @factory.build
|
401
|
-
assert_equal
|
471
|
+
assert_equal saved, instance
|
402
472
|
end
|
403
473
|
end
|
404
474
|
|
405
475
|
context "and an after_create callback has been registered" do
|
476
|
+
saved = nil
|
406
477
|
setup do
|
407
|
-
@the_block = lambda {|user| assert !user.new_record?;
|
408
|
-
|
478
|
+
@the_block = lambda {|user| assert !user.new_record?; saved = user}
|
479
|
+
|
409
480
|
@factory.after_create &@the_block
|
410
481
|
end
|
411
|
-
|
482
|
+
|
412
483
|
should "not call the callback when the object is built" do
|
413
484
|
@the_block.expects(:call).never
|
414
485
|
@factory.build
|
415
486
|
end
|
416
487
|
|
417
488
|
should "call the callback when the object is created" do
|
418
|
-
@
|
489
|
+
@factory.expects(:instance_exec)
|
490
|
+
@factory.create
|
491
|
+
end
|
492
|
+
|
493
|
+
should "yield the instance to block if block arity is <= 1" do
|
494
|
+
@factory.after_create(&(lambda{|user|}))
|
495
|
+
@factory.expects(:instance_exec).with(anything)
|
496
|
+
@factory.create
|
497
|
+
end
|
498
|
+
|
499
|
+
should "yield the instance and attrs to block if block arity is > 1" do
|
500
|
+
@factory.after_create(&(lambda{|user,attrs|}))
|
501
|
+
@factory.expects(:instance_exec).with(anything, instance_of(Hash))
|
419
502
|
@factory.create
|
420
503
|
end
|
421
504
|
|
422
505
|
should "yield the instance to the callback when called" do
|
423
506
|
instance = @factory.create
|
424
|
-
assert_equal
|
507
|
+
assert_equal saved, instance
|
425
508
|
end
|
426
509
|
end
|
427
510
|
|
428
511
|
context "and both after_build and after_create callbacks have been registered" do
|
512
|
+
post_build, = post_create = nil
|
429
513
|
setup do
|
430
|
-
|
431
|
-
@
|
432
|
-
|
514
|
+
test = self
|
515
|
+
@the_after_build_block = lambda {|user| test.assert(user.new_record?); post_build = user}
|
516
|
+
@the_after_create_block = lambda {|user| test.assert(!user.new_record?); post_create = user}
|
517
|
+
|
433
518
|
@factory.after_build &@the_after_build_block
|
434
519
|
@factory.after_create &@the_after_create_block
|
435
520
|
end
|
436
|
-
|
521
|
+
|
437
522
|
should "only call the after_build callback when the object is built" do
|
438
|
-
@
|
439
|
-
@the_after_create_block.expects(:call).never
|
523
|
+
@factory.expects(:instance_exec).once
|
440
524
|
@factory.build
|
441
525
|
end
|
442
526
|
|
443
527
|
should "call both callbacks when the object is created" do
|
444
|
-
@
|
445
|
-
@the_after_create_block.expects(:call).once
|
528
|
+
@factory.expects(:instance_exec).at_least(2)
|
446
529
|
@factory.create
|
447
530
|
end
|
448
531
|
|
449
532
|
should "yield the same instance to each callback when called" do
|
450
533
|
instance = @factory.create
|
451
|
-
assert_equal
|
452
|
-
assert_equal
|
453
|
-
assert_equal
|
534
|
+
assert_equal post_build, instance
|
535
|
+
assert_equal post_create, instance
|
536
|
+
assert_equal post_create, post_build
|
454
537
|
end
|
455
|
-
|
538
|
+
|
456
539
|
should "call the after_build callback before the after_create callback when objects are created" do
|
457
540
|
# TODO - is this good enough to detect "beforeness"?
|
458
|
-
|
459
|
-
@
|
460
|
-
|
541
|
+
test = self
|
542
|
+
@the_after_build_block = lambda {|user| test.assert_nil @post_build; test.assert_nil @post_create; @post_build = user}
|
543
|
+
@the_after_create_block = lambda {|user| test.assert_not_nil @post_build; test.assert_nil @post_create; @post_create = user}
|
544
|
+
|
461
545
|
@factory.after_build &@the_after_build_block
|
462
546
|
@factory.after_create &@the_after_create_block
|
463
547
|
@factory.create
|
@@ -477,7 +561,7 @@ class FactoryTest < Test::Unit::TestCase
|
|
477
561
|
end
|
478
562
|
|
479
563
|
end
|
480
|
-
|
564
|
+
|
481
565
|
context "when creating an instance" do
|
482
566
|
|
483
567
|
setup do
|
data/test/models.rb
CHANGED
@@ -22,6 +22,7 @@ end
|
|
22
22
|
CreateSchema.suppress_messages { CreateSchema.migrate(:up) }
|
23
23
|
|
24
24
|
class User < ActiveRecord::Base
|
25
|
+
attr_accessor :foo, :snafu
|
25
26
|
validates_presence_of :first_name, :last_name, :email
|
26
27
|
has_many :posts, :foreign_key => 'author_id', :validate => false
|
27
28
|
end
|