factory_bot 5.1.1 → 6.0.1
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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +52 -13
- data/GETTING_STARTED.md +426 -68
- data/NEWS.md +18 -1
- data/README.md +4 -4
- data/lib/factory_bot/aliases.rb +3 -3
- data/lib/factory_bot/attribute/association.rb +2 -2
- data/lib/factory_bot/attribute/dynamic.rb +2 -1
- data/lib/factory_bot/attribute_assigner.rb +9 -10
- data/lib/factory_bot/attribute_list.rb +1 -1
- data/lib/factory_bot/callback.rb +2 -10
- data/lib/factory_bot/configuration.rb +6 -6
- data/lib/factory_bot/declaration.rb +1 -1
- data/lib/factory_bot/declaration_list.rb +2 -2
- data/lib/factory_bot/decorator/invocation_tracker.rb +1 -1
- data/lib/factory_bot/decorator.rb +1 -1
- data/lib/factory_bot/definition.rb +42 -16
- data/lib/factory_bot/definition_hierarchy.rb +1 -11
- data/lib/factory_bot/definition_proxy.rb +64 -6
- data/lib/factory_bot/enum.rb +27 -0
- data/lib/factory_bot/evaluator.rb +5 -7
- data/lib/factory_bot/evaluator_class_definer.rb +1 -1
- data/lib/factory_bot/factory.rb +12 -12
- data/lib/factory_bot/factory_runner.rb +3 -3
- data/lib/factory_bot/find_definitions.rb +1 -1
- data/lib/factory_bot/internal.rb +18 -29
- data/lib/factory_bot/linter.rb +9 -13
- data/lib/factory_bot/null_factory.rb +10 -4
- data/lib/factory_bot/null_object.rb +2 -6
- data/lib/factory_bot/registry.rb +4 -4
- data/lib/factory_bot/reload.rb +0 -1
- data/lib/factory_bot/sequence.rb +5 -5
- data/lib/factory_bot/strategy/null.rb +4 -2
- data/lib/factory_bot/strategy/stub.rb +6 -2
- data/lib/factory_bot/strategy_syntax_method_registrar.rb +12 -1
- data/lib/factory_bot/syntax/default.rb +7 -19
- data/lib/factory_bot/trait.rb +1 -1
- data/lib/factory_bot/version.rb +1 -1
- data/lib/factory_bot.rb +21 -55
- metadata +12 -11
data/GETTING_STARTED.md
CHANGED
@@ -1,8 +1,87 @@
|
|
1
1
|
Getting Started
|
2
2
|
===============
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
* [Setup](#setup)
|
5
|
+
+ [Update Your Gemfile](#update-your-gemfile)
|
6
|
+
+ [Configure your test suite](#configure-your-test-suite)
|
7
|
+
- [RSpec](#rspec)
|
8
|
+
- [Test::Unit](#testunit)
|
9
|
+
- [Cucumber](#cucumber)
|
10
|
+
- [Spinach](#spinach)
|
11
|
+
- [Minitest](#minitest)
|
12
|
+
- [Minitest::Spec](#minitestspec)
|
13
|
+
- [minitest-rails](#minitest-rails)
|
14
|
+
* [Defining factories](#defining-factories)
|
15
|
+
+ [Factory name and attributes](#factory-name-and-attributes)
|
16
|
+
+ [Specifying the class explicitly](#specifying-the-class-explicitly)
|
17
|
+
+ [Hash attributes](#hash-attributes)
|
18
|
+
+ [Best practices](#best-practices)
|
19
|
+
+ [Definition file paths](#definition-file-paths)
|
20
|
+
+ [Static Attributes](#static-attributes)
|
21
|
+
* [Using factories](#using-factories)
|
22
|
+
+ [Build strategies](#build-strategies)
|
23
|
+
+ [Attribute overrides](#attribute-overrides)
|
24
|
+
+ [`build_stubbed` and `Marshal.dump`](#build_stubbed-and-marshaldump)
|
25
|
+
* [Aliases](#aliases)
|
26
|
+
* [Dependent Attributes](#dependent-attributes)
|
27
|
+
* [Transient Attributes](#transient-attributes)
|
28
|
+
+ [With other attributes](#with-other-attributes)
|
29
|
+
+ [With `attributes_for`](#with-attributes_for)
|
30
|
+
+ [With callbacks](#with-callbacks)
|
31
|
+
+ [With associations](#with-associations)
|
32
|
+
* [Method Name / Reserved Word Attributes](#method-name--reserved-word-attributes)
|
33
|
+
* [Inheritance](#inheritance)
|
34
|
+
+ [Nested factories](#nested-factories)
|
35
|
+
+ [Assigning parent explicitly](#assigning-parent-explicitly)
|
36
|
+
+ [Best practices](#best-practices-1)
|
37
|
+
* [Associations](#associations)
|
38
|
+
+ [Implicit definition](#implicit-definition)
|
39
|
+
+ [Explicit definition](#explicit-definition)
|
40
|
+
+ [Specifying the factory](#specifying-the-factory)
|
41
|
+
+ [Overriding attributes](#overriding-attributes)
|
42
|
+
+ [Build strategies](#build-strategies-1)
|
43
|
+
+ [`has_many` associations](#has_many-associations)
|
44
|
+
+ [`has_and_belongs_to_many` associations](#has_and_belongs_to_many-associations)
|
45
|
+
+ [Polymorphic associations](#polymorphic-associations)
|
46
|
+
* [Sequences](#sequences)
|
47
|
+
+ [Global sequences](#global-sequences)
|
48
|
+
+ [With dynamic attributes](#with-dynamic-attributes)
|
49
|
+
+ [As implicit attributes](#as-implicit-attributes)
|
50
|
+
+ [Inline sequences](#inline-sequences)
|
51
|
+
+ [Initial value](#initial-value)
|
52
|
+
+ [Without a block](#without-a-block)
|
53
|
+
+ [Aliases](#aliases-1)
|
54
|
+
+ [Rewinding](#rewinding)
|
55
|
+
* [Traits](#traits)
|
56
|
+
+ [Defining traits](#defining-traits)
|
57
|
+
+ [As implicit attributes](#as-implicit-attributes-1)
|
58
|
+
+ [Attribute precedence](#attribute-precedence)
|
59
|
+
+ [In child factories](#in-child-factories)
|
60
|
+
+ [Using traits](#using-traits)
|
61
|
+
+ [With associations](#with-associations-1)
|
62
|
+
+ [Traits within traits](#traits-within-traits)
|
63
|
+
+ [With transient attributes](#with-transient-attributes)
|
64
|
+
+ [Enum traits](#enum-traits)
|
65
|
+
* [Callbacks](#callbacks)
|
66
|
+
+ [Default callbacks](#default-callbacks)
|
67
|
+
+ [Multiple callbacks](#multiple-callbacks)
|
68
|
+
+ [Global callbacks](#global-callbacks)
|
69
|
+
+ [Symbol#to_proc](#symbolto_proc)
|
70
|
+
* [Modifying factories](#modifying-factories)
|
71
|
+
* [Building or Creating Multiple Records](#building-or-creating-multiple-records)
|
72
|
+
* [Linting Factories](#linting-factories)
|
73
|
+
* [Custom Construction](#custom-construction)
|
74
|
+
* [Custom Strategies](#custom-strategies)
|
75
|
+
* [Custom Callbacks](#custom-callbacks)
|
76
|
+
* [Custom Methods to Persist Objects](#custom-methods-to-persist-objects)
|
77
|
+
* [ActiveSupport Instrumentation](#activesupport-instrumentation)
|
78
|
+
* [Rails Preloaders and RSpec](#rails-preloaders-and-rspec)
|
79
|
+
* [Using Without Bundler](#using-without-bundler)
|
80
|
+
|
81
|
+
Setup
|
82
|
+
-----
|
83
|
+
|
84
|
+
### Update Your Gemfile
|
6
85
|
|
7
86
|
If you're using Rails:
|
8
87
|
|
@@ -16,21 +95,13 @@ If you're *not* using Rails:
|
|
16
95
|
gem "factory_bot"
|
17
96
|
```
|
18
97
|
|
19
|
-
|
20
|
-
JRuby has to be used in 1.9 mode, for that, use JRUBY_OPTS environment variable:
|
21
|
-
|
22
|
-
```bash
|
23
|
-
export JRUBY_OPTS=--1.9
|
24
|
-
```
|
25
|
-
|
26
|
-
Once your Gemfile is updated, you'll want to update your bundle.
|
27
|
-
|
28
|
-
Configure your test suite
|
29
|
-
-------------------------
|
98
|
+
### Configure your test suite
|
30
99
|
|
31
|
-
|
100
|
+
#### RSpec
|
32
101
|
|
33
|
-
If you're using Rails, add the following configuration to
|
102
|
+
If you're using Rails, add the following configuration to
|
103
|
+
`spec/support/factory_bot.rb` and be sure to require that file in
|
104
|
+
`rails_helper.rb`:
|
34
105
|
|
35
106
|
```ruby
|
36
107
|
RSpec.configure do |config|
|
@@ -50,7 +121,7 @@ RSpec.configure do |config|
|
|
50
121
|
end
|
51
122
|
```
|
52
123
|
|
53
|
-
|
124
|
+
#### Test::Unit
|
54
125
|
|
55
126
|
```ruby
|
56
127
|
class Test::Unit::TestCase
|
@@ -58,14 +129,14 @@ class Test::Unit::TestCase
|
|
58
129
|
end
|
59
130
|
```
|
60
131
|
|
61
|
-
|
132
|
+
#### Cucumber
|
62
133
|
|
63
134
|
```ruby
|
64
135
|
# env.rb (Rails example location - RAILS_ROOT/features/support/env.rb)
|
65
136
|
World(FactoryBot::Syntax::Methods)
|
66
137
|
```
|
67
138
|
|
68
|
-
|
139
|
+
#### Spinach
|
69
140
|
|
70
141
|
```ruby
|
71
142
|
class Spinach::FeatureSteps
|
@@ -73,7 +144,7 @@ class Spinach::FeatureSteps
|
|
73
144
|
end
|
74
145
|
```
|
75
146
|
|
76
|
-
|
147
|
+
#### Minitest
|
77
148
|
|
78
149
|
```ruby
|
79
150
|
class Minitest::Unit::TestCase
|
@@ -81,7 +152,7 @@ class Minitest::Unit::TestCase
|
|
81
152
|
end
|
82
153
|
```
|
83
154
|
|
84
|
-
|
155
|
+
#### Minitest::Spec
|
85
156
|
|
86
157
|
```ruby
|
87
158
|
class Minitest::Spec
|
@@ -89,7 +160,7 @@ class Minitest::Spec
|
|
89
160
|
end
|
90
161
|
```
|
91
162
|
|
92
|
-
|
163
|
+
#### minitest-rails
|
93
164
|
|
94
165
|
```ruby
|
95
166
|
class ActiveSupport::TestCase
|
@@ -97,12 +168,16 @@ class ActiveSupport::TestCase
|
|
97
168
|
end
|
98
169
|
```
|
99
170
|
|
100
|
-
If you do not include `FactoryBot::Syntax::Methods` in your test suite, then all
|
171
|
+
If you do not include `FactoryBot::Syntax::Methods` in your test suite, then all
|
172
|
+
factory\_bot methods will need to be prefaced with `FactoryBot`.
|
101
173
|
|
102
174
|
Defining factories
|
103
175
|
------------------
|
104
176
|
|
105
|
-
|
177
|
+
### Factory name and attributes
|
178
|
+
|
179
|
+
Each factory has a name and a set of attributes. The name is used to guess the
|
180
|
+
class of the object by default:
|
106
181
|
|
107
182
|
```ruby
|
108
183
|
# This will guess the User class
|
@@ -115,6 +190,8 @@ FactoryBot.define do
|
|
115
190
|
end
|
116
191
|
```
|
117
192
|
|
193
|
+
### Specifying the class explicitly
|
194
|
+
|
118
195
|
It is also possible to explicitly specify the class:
|
119
196
|
|
120
197
|
```ruby
|
@@ -125,13 +202,15 @@ factory :admin, class: User
|
|
125
202
|
If the constant is not available
|
126
203
|
(if you are using a Rails engine that waits to load models, for example),
|
127
204
|
you can also pass a symbol or string,
|
128
|
-
which
|
205
|
+
which factory\_bot will constantize later, once you start building objects:
|
129
206
|
|
130
207
|
```ruby
|
131
208
|
# It's OK if Doorkeeper::AccessToken isn't loaded yet
|
132
209
|
factory :access_token, class: "Doorkeeper::AccessToken"
|
133
210
|
```
|
134
211
|
|
212
|
+
### Hash attributes
|
213
|
+
|
135
214
|
Because of the block syntax in Ruby, defining attributes as `Hash`es (for
|
136
215
|
serialized/JSON columns, for example) requires two sets of curly brackets:
|
137
216
|
|
@@ -141,10 +220,19 @@ factory :program do
|
|
141
220
|
end
|
142
221
|
```
|
143
222
|
|
144
|
-
|
223
|
+
### Best practices
|
224
|
+
|
225
|
+
It is recommended that you have one factory for each class that provides
|
226
|
+
the simplest set of attributes necessary to create an instance of that class. If
|
227
|
+
you're creating ActiveRecord objects, that means that you should only provide
|
228
|
+
attributes that are required through validations and that do not have defaults.
|
229
|
+
Other factories can be created through inheritance to cover common scenarios for
|
230
|
+
each class.
|
145
231
|
|
146
232
|
Attempting to define multiple factories with the same name will raise an error.
|
147
233
|
|
234
|
+
### Definition file paths
|
235
|
+
|
148
236
|
Factories can be defined anywhere, but will be automatically loaded after
|
149
237
|
calling `FactoryBot.find_definitions` if factories are defined in files at the
|
150
238
|
following locations:
|
@@ -154,10 +242,20 @@ following locations:
|
|
154
242
|
test/factories/*.rb
|
155
243
|
spec/factories/*.rb
|
156
244
|
|
245
|
+
### Static Attributes
|
246
|
+
|
247
|
+
Static attributes (without a block) are no longer available in factory\_bot 5.
|
248
|
+
You can read more about the decision to remove them in
|
249
|
+
[this blog post](https://robots.thoughtbot.com/deprecating-static-attributes-in-factory_bot-4-11).
|
250
|
+
|
251
|
+
|
157
252
|
Using factories
|
158
253
|
---------------
|
159
254
|
|
160
|
-
|
255
|
+
### Build strategies
|
256
|
+
|
257
|
+
factory\_bot supports several different build strategies: build, create,
|
258
|
+
attributes\_for and build\_stubbed:
|
161
259
|
|
162
260
|
```ruby
|
163
261
|
# Returns a User instance that's not saved
|
@@ -178,7 +276,10 @@ create(:user) do |user|
|
|
178
276
|
end
|
179
277
|
```
|
180
278
|
|
181
|
-
|
279
|
+
### Attribute overrides
|
280
|
+
|
281
|
+
No matter which strategy is used, it's possible to override the defined
|
282
|
+
attributes by passing a hash:
|
182
283
|
|
183
284
|
```ruby
|
184
285
|
# Build a User instance and override the first_name property
|
@@ -187,19 +288,20 @@ user.first_name
|
|
187
288
|
# => "Joe"
|
188
289
|
```
|
189
290
|
|
190
|
-
|
191
|
-
`Marshal.dump`, since factory_bot defines singleton methods on these objects.
|
291
|
+
### `build_stubbed` and `Marshal.dump`
|
192
292
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
Static attributes (without a block) are no longer available in factory\_bot 5.
|
197
|
-
You can read more about the decision to remove them in
|
198
|
-
[this blog post](https://robots.thoughtbot.com/deprecating-static-attributes-in-factory_bot-4-11).
|
293
|
+
Note that objects created with `build_stubbed` cannot be serialized with
|
294
|
+
`Marshal.dump`, since factory\_bot defines singleton methods on these objects.
|
199
295
|
|
200
296
|
Aliases
|
201
297
|
-------
|
202
|
-
|
298
|
+
|
299
|
+
factory\_bot allows you to define aliases to existing factories to make them
|
300
|
+
easier to re-use. This could come in handy when, for example, your Post object
|
301
|
+
has an author attribute that actually refers to an instance of a User class.
|
302
|
+
While normally factory\_bot can infer the factory name from the association name,
|
303
|
+
in this case it will look for an author factory in vain. So, alias your user
|
304
|
+
factory so it can be used under alias names.
|
203
305
|
|
204
306
|
```ruby
|
205
307
|
factory :user, aliases: [:author, :commenter] do
|
@@ -244,35 +346,77 @@ create(:user, last_name: "Doe").email
|
|
244
346
|
Transient Attributes
|
245
347
|
--------------------
|
246
348
|
|
247
|
-
|
349
|
+
### With other attributes
|
350
|
+
|
351
|
+
There may be times where your code can be DRYed up by passing in transient
|
352
|
+
attributes to factories. You can access transient attributes within other
|
353
|
+
attributes (see [Dependent Attributes](#dependent-attributes)):
|
248
354
|
|
249
355
|
```ruby
|
250
356
|
factory :user do
|
251
357
|
transient do
|
252
358
|
rockstar { true }
|
253
|
-
upcased { false }
|
254
359
|
end
|
255
360
|
|
256
361
|
name { "John Doe#{" - Rockstar" if rockstar}" }
|
257
|
-
|
362
|
+
end
|
363
|
+
|
364
|
+
create(:user).name
|
365
|
+
#=> "John Doe - ROCKSTAR"
|
366
|
+
|
367
|
+
create(:user, rockstar: false).name
|
368
|
+
#=> "John Doe"
|
369
|
+
```
|
370
|
+
|
371
|
+
### With `attributes_for`
|
372
|
+
|
373
|
+
Transient attributes will be ignored within attributes\_for and won't be set on
|
374
|
+
the model, even if the attribute exists or you attempt to override it.
|
375
|
+
|
376
|
+
### With callbacks
|
377
|
+
|
378
|
+
If you need to access the evaluator in a factory\_bot callback,
|
379
|
+
you'll need to declare a second block argument (for the evaluator) and access
|
380
|
+
transient attributes from there.
|
381
|
+
|
382
|
+
```ruby
|
383
|
+
factory :user do
|
384
|
+
transient do
|
385
|
+
upcased { false }
|
386
|
+
end
|
387
|
+
|
388
|
+
name { "John Doe" }
|
258
389
|
|
259
390
|
after(:create) do |user, evaluator|
|
260
391
|
user.name.upcase! if evaluator.upcased
|
261
392
|
end
|
262
393
|
end
|
263
394
|
|
395
|
+
create(:user).name
|
396
|
+
#=> "John Doe"
|
397
|
+
|
264
398
|
create(:user, upcased: true).name
|
265
|
-
#=> "JOHN DOE
|
399
|
+
#=> "JOHN DOE"
|
266
400
|
```
|
267
401
|
|
268
|
-
|
269
|
-
set on the model,
|
270
|
-
even if the attribute exists or you attempt to override it.
|
402
|
+
### With associations
|
271
403
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
404
|
+
Transient [associations](#associations) are not supported in factory\_bot.
|
405
|
+
Associations within the transient block will be treated as regular,
|
406
|
+
non-transient associations.
|
407
|
+
|
408
|
+
If needed, you can generally work around this by building a factory within a
|
409
|
+
transient attribute:
|
410
|
+
|
411
|
+
```ruby
|
412
|
+
factory :post
|
413
|
+
|
414
|
+
factory :user do
|
415
|
+
transient do
|
416
|
+
post { build(:post) }
|
417
|
+
end
|
418
|
+
end
|
419
|
+
```
|
276
420
|
|
277
421
|
Method Name / Reserved Word Attributes
|
278
422
|
-------------------------------
|
@@ -293,7 +437,10 @@ end
|
|
293
437
|
Inheritance
|
294
438
|
-----------
|
295
439
|
|
296
|
-
|
440
|
+
### Nested factories
|
441
|
+
|
442
|
+
You can easily create multiple factories for the same class without repeating
|
443
|
+
common attributes by nesting factories:
|
297
444
|
|
298
445
|
```ruby
|
299
446
|
factory :post do
|
@@ -309,6 +456,8 @@ approved_post.title # => "A title"
|
|
309
456
|
approved_post.approved # => true
|
310
457
|
```
|
311
458
|
|
459
|
+
### Assigning parent explicitly
|
460
|
+
|
312
461
|
You can also assign the parent explicitly:
|
313
462
|
|
314
463
|
```ruby
|
@@ -321,6 +470,8 @@ factory :approved_post, parent: :post do
|
|
321
470
|
end
|
322
471
|
```
|
323
472
|
|
473
|
+
### Best practices
|
474
|
+
|
324
475
|
As mentioned above, it's good practice to define a basic factory for each class
|
325
476
|
with only the attributes required to create it. Then, create more specific
|
326
477
|
factories that inherit from this basic parent. Factory definitions are still
|
@@ -329,7 +480,10 @@ code, so keep them DRY.
|
|
329
480
|
Associations
|
330
481
|
------------
|
331
482
|
|
332
|
-
|
483
|
+
### Implicit definition
|
484
|
+
|
485
|
+
It's possible to set up associations within factories. If the factory name is
|
486
|
+
the same as the association name, the factory name can be left out.
|
333
487
|
|
334
488
|
```ruby
|
335
489
|
factory :post do
|
@@ -338,15 +492,66 @@ factory :post do
|
|
338
492
|
end
|
339
493
|
```
|
340
494
|
|
341
|
-
|
495
|
+
### Explicit definition
|
496
|
+
|
497
|
+
You can define associations explicitly. This can be handy especially when
|
498
|
+
[Overriding attributes](#overriding-attributes)
|
342
499
|
|
343
500
|
```ruby
|
344
501
|
factory :post do
|
345
502
|
# ...
|
346
|
-
association :author
|
503
|
+
association :author
|
347
504
|
end
|
348
505
|
```
|
349
506
|
|
507
|
+
### Specifying the factory
|
508
|
+
|
509
|
+
You can specify a different factory (although [Aliases](#aliases) might also
|
510
|
+
help you out here).
|
511
|
+
|
512
|
+
Implicitly:
|
513
|
+
|
514
|
+
```ruby
|
515
|
+
factory :post do
|
516
|
+
# ...
|
517
|
+
author factory: :user
|
518
|
+
end
|
519
|
+
```
|
520
|
+
|
521
|
+
Explicitly:
|
522
|
+
|
523
|
+
```ruby
|
524
|
+
factory :post do
|
525
|
+
# ...
|
526
|
+
association :author, factory: :user
|
527
|
+
end
|
528
|
+
```
|
529
|
+
|
530
|
+
### Overriding attributes
|
531
|
+
|
532
|
+
You can also override attributes.
|
533
|
+
|
534
|
+
Implicitly:
|
535
|
+
|
536
|
+
```ruby
|
537
|
+
factory :post do
|
538
|
+
# ...
|
539
|
+
author factory: :author, last_name: "Writely"
|
540
|
+
end
|
541
|
+
```
|
542
|
+
|
543
|
+
Explicitly:
|
544
|
+
|
545
|
+
|
546
|
+
```ruby
|
547
|
+
factory :post do
|
548
|
+
# ...
|
549
|
+
association :author, last_name: "Writely"
|
550
|
+
end
|
551
|
+
```
|
552
|
+
|
553
|
+
### Build strategies
|
554
|
+
|
350
555
|
In factory\_bot 5, associations default to using the same build strategy as
|
351
556
|
their parent object:
|
352
557
|
|
@@ -412,6 +617,8 @@ factory :post do
|
|
412
617
|
author strategy: :build # <<< this does *not* work; causes author_id to be nil
|
413
618
|
```
|
414
619
|
|
620
|
+
### `has_many` associations
|
621
|
+
|
415
622
|
Generating data for a `has_many` relationship is a bit more involved,
|
416
623
|
depending on the amount of flexibility desired, but here's a surefire example
|
417
624
|
of generating associated data.
|
@@ -457,6 +664,8 @@ create(:user_with_posts).posts.length # 5
|
|
457
664
|
create(:user_with_posts, posts_count: 15).posts.length # 15
|
458
665
|
```
|
459
666
|
|
667
|
+
### `has_and_belongs_to_many` associations
|
668
|
+
|
460
669
|
Generating data for a `has_and_belongs_to_many` relationship is very similar
|
461
670
|
to the above `has_many` relationship, with a small change, you need to pass an
|
462
671
|
array of objects to the model's pluralized attribute name rather than a single
|
@@ -508,6 +717,8 @@ create(:profile_with_languages).languages.length # 5
|
|
508
717
|
create(:profile_with_languages, languages_count: 15).languages.length # 15
|
509
718
|
```
|
510
719
|
|
720
|
+
### Polymorphic associations
|
721
|
+
|
511
722
|
Polymorphic associations can be handled with traits:
|
512
723
|
|
513
724
|
```ruby
|
@@ -541,6 +752,8 @@ create(:comment, :for_photo)
|
|
541
752
|
Sequences
|
542
753
|
---------
|
543
754
|
|
755
|
+
### Global sequences
|
756
|
+
|
544
757
|
Unique values in a specific format (for example, e-mail addresses) can be
|
545
758
|
generated using sequences. Sequences are defined by calling `sequence` in a
|
546
759
|
definition block, and values in a sequence are generated by calling
|
@@ -561,6 +774,8 @@ generate :email
|
|
561
774
|
# => "person2@example.com"
|
562
775
|
```
|
563
776
|
|
777
|
+
### With dynamic attributes
|
778
|
+
|
564
779
|
Sequences can be used in dynamic attributes:
|
565
780
|
|
566
781
|
```ruby
|
@@ -569,6 +784,8 @@ factory :invite do
|
|
569
784
|
end
|
570
785
|
```
|
571
786
|
|
787
|
+
### As implicit attributes
|
788
|
+
|
572
789
|
Or as implicit attributes:
|
573
790
|
|
574
791
|
```ruby
|
@@ -580,6 +797,8 @@ end
|
|
580
797
|
Note that defining sequences as implicit attributes will not work if you have a
|
581
798
|
factory with the same name as the sequence.
|
582
799
|
|
800
|
+
### Inline sequences
|
801
|
+
|
583
802
|
And it's also possible to define an in-line sequence that is only used in
|
584
803
|
a particular factory:
|
585
804
|
|
@@ -589,7 +808,10 @@ factory :user do
|
|
589
808
|
end
|
590
809
|
```
|
591
810
|
|
592
|
-
|
811
|
+
### Initial value
|
812
|
+
|
813
|
+
You can override the initial value. Any value that response to the `#next`
|
814
|
+
method will work (e.g. 1, 2, 3, 'a', 'b', 'c')
|
593
815
|
|
594
816
|
```ruby
|
595
817
|
factory :user do
|
@@ -597,6 +819,8 @@ factory :user do
|
|
597
819
|
end
|
598
820
|
```
|
599
821
|
|
822
|
+
### Without a block
|
823
|
+
|
600
824
|
Without a block, the value will increment itself, starting at its initial value:
|
601
825
|
|
602
826
|
```ruby
|
@@ -605,6 +829,8 @@ factory :post do
|
|
605
829
|
end
|
606
830
|
```
|
607
831
|
|
832
|
+
### Aliases
|
833
|
+
|
608
834
|
Sequences can also have aliases. The sequence aliases share the same counter:
|
609
835
|
|
610
836
|
```ruby
|
@@ -634,6 +860,8 @@ end
|
|
634
860
|
|
635
861
|
The value just needs to support the `#next` method. Here the next value will be 'a', then 'b', etc.
|
636
862
|
|
863
|
+
### Rewinding
|
864
|
+
|
637
865
|
Sequences can also be rewound with `FactoryBot.rewind_sequences`:
|
638
866
|
|
639
867
|
```ruby
|
@@ -653,6 +881,8 @@ This rewinds all registered sequences.
|
|
653
881
|
Traits
|
654
882
|
------
|
655
883
|
|
884
|
+
### Defining traits
|
885
|
+
|
656
886
|
Traits allow you to group attributes together and then apply them
|
657
887
|
to any factory.
|
658
888
|
|
@@ -688,6 +918,8 @@ factory :story do
|
|
688
918
|
end
|
689
919
|
```
|
690
920
|
|
921
|
+
### As implicit attributes
|
922
|
+
|
691
923
|
Traits can be used as implicit attributes:
|
692
924
|
|
693
925
|
```ruby
|
@@ -701,6 +933,8 @@ end
|
|
701
933
|
Note that defining traits as implicit attributes will not work if you have a
|
702
934
|
factory or sequence with the same name as the trait.
|
703
935
|
|
936
|
+
### Attribute precedence
|
937
|
+
|
704
938
|
Traits that define the same attributes won't raise AttributeDefinitionErrors;
|
705
939
|
the trait that defines the attribute latest gets precedence.
|
706
940
|
|
@@ -731,7 +965,9 @@ factory :user do
|
|
731
965
|
end
|
732
966
|
```
|
733
967
|
|
734
|
-
|
968
|
+
### In child factories
|
969
|
+
|
970
|
+
You can override individual attributes granted by a trait in a child factory:
|
735
971
|
|
736
972
|
```ruby
|
737
973
|
factory :user do
|
@@ -751,7 +987,10 @@ factory :user do
|
|
751
987
|
end
|
752
988
|
```
|
753
989
|
|
754
|
-
|
990
|
+
### Using traits
|
991
|
+
|
992
|
+
Traits can also be passed in as a list of symbols when you construct an instance
|
993
|
+
from factory\_bot.
|
755
994
|
|
756
995
|
```ruby
|
757
996
|
factory :user do
|
@@ -790,6 +1029,8 @@ end
|
|
790
1029
|
create_list(:user, 3, :admin, :male, name: "Jon Snow")
|
791
1030
|
```
|
792
1031
|
|
1032
|
+
### With associations
|
1033
|
+
|
793
1034
|
Traits can be used with associations easily too:
|
794
1035
|
|
795
1036
|
```ruby
|
@@ -830,6 +1071,8 @@ end
|
|
830
1071
|
create(:post).author
|
831
1072
|
```
|
832
1073
|
|
1074
|
+
### Traits within traits
|
1075
|
+
|
833
1076
|
Traits can be used within other traits to mix in their attributes.
|
834
1077
|
|
835
1078
|
```ruby
|
@@ -845,6 +1088,8 @@ factory :order do
|
|
845
1088
|
end
|
846
1089
|
```
|
847
1090
|
|
1091
|
+
### With transient attributes
|
1092
|
+
|
848
1093
|
Finally, traits can accept transient attributes.
|
849
1094
|
|
850
1095
|
```ruby
|
@@ -863,9 +1108,103 @@ end
|
|
863
1108
|
create :invoice, :with_amount, amount: 2
|
864
1109
|
```
|
865
1110
|
|
1111
|
+
### Enum traits
|
1112
|
+
|
1113
|
+
Given an Active Record model with an enum attribute:
|
1114
|
+
|
1115
|
+
```rb
|
1116
|
+
class Task < ActiveRecord::Base
|
1117
|
+
enum status: {queued: 0, started: 1, finished: 2}
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
```
|
1121
|
+
|
1122
|
+
factory\_bot will automatically define traits for each possible value of the
|
1123
|
+
enum:
|
1124
|
+
|
1125
|
+
```rb
|
1126
|
+
FactoryBot.define do
|
1127
|
+
factory :task
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
FactoryBot.build(:task, :queued)
|
1131
|
+
FactoryBot.build(:task, :started)
|
1132
|
+
FactoryBot.build(:task, :finished)
|
1133
|
+
```
|
1134
|
+
|
1135
|
+
Writing the traits out manually would be cumbersome, and is not necessary:
|
1136
|
+
|
1137
|
+
```rb
|
1138
|
+
FactoryBot.define do
|
1139
|
+
factory :task do
|
1140
|
+
trait :queued do
|
1141
|
+
status { :queued }
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
trait :started do
|
1145
|
+
status { :started }
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
trait :finished do
|
1149
|
+
status { :finished }
|
1150
|
+
end
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
```
|
1154
|
+
|
1155
|
+
If automatically defining traits for enum attributes on every factory is not
|
1156
|
+
desired, it is possible to disable the feature by setting
|
1157
|
+
`FactoryBot.automatically_define_enum_traits = false`
|
1158
|
+
|
1159
|
+
In that case, it is still possible to explicitly define traits for an enum
|
1160
|
+
attribute in a particular factory:
|
1161
|
+
|
1162
|
+
```rb
|
1163
|
+
FactoryBot.automatically_define_enum_traits = false
|
1164
|
+
|
1165
|
+
FactoryBot.define do
|
1166
|
+
factory :task do
|
1167
|
+
traits_for_enum(:status)
|
1168
|
+
end
|
1169
|
+
end
|
1170
|
+
```
|
1171
|
+
|
1172
|
+
It is also possible to use this feature for other enumerable values, not
|
1173
|
+
specifically tied to Active Record enum attributes.
|
1174
|
+
|
1175
|
+
With an array:
|
1176
|
+
|
1177
|
+
```rb
|
1178
|
+
class Task
|
1179
|
+
attr_accessor :status
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
FactoryBot.define do
|
1183
|
+
factory :task do
|
1184
|
+
traits_for_enum(:status, ["queued", "started", "finished"])
|
1185
|
+
end
|
1186
|
+
end
|
1187
|
+
```
|
1188
|
+
|
1189
|
+
Or with a hash:
|
1190
|
+
|
1191
|
+
```rb
|
1192
|
+
class Task
|
1193
|
+
attr_accessor :status
|
1194
|
+
end
|
1195
|
+
|
1196
|
+
FactoryBot.define do
|
1197
|
+
factory :task do
|
1198
|
+
traits_for_enum(:status, { queued: 0, started: 1, finished: 2 })
|
1199
|
+
end
|
1200
|
+
end
|
1201
|
+
```
|
1202
|
+
|
866
1203
|
Callbacks
|
867
1204
|
---------
|
868
1205
|
|
1206
|
+
### Default callbacks
|
1207
|
+
|
869
1208
|
factory\_bot makes available four callbacks for injecting some code:
|
870
1209
|
|
871
1210
|
* after(:build) - called after a factory is built (via `FactoryBot.build`, `FactoryBot.create`)
|
@@ -884,6 +1223,8 @@ end
|
|
884
1223
|
|
885
1224
|
Note that you'll have an instance of the user in the block. This can be useful.
|
886
1225
|
|
1226
|
+
### Multiple callbacks
|
1227
|
+
|
887
1228
|
You can also define multiple types of callbacks on the same factory:
|
888
1229
|
|
889
1230
|
```ruby
|
@@ -893,7 +1234,8 @@ factory :user do
|
|
893
1234
|
end
|
894
1235
|
```
|
895
1236
|
|
896
|
-
Factories can also define any number of the same kind of callback. These
|
1237
|
+
Factories can also define any number of the same kind of callback. These
|
1238
|
+
callbacks will be executed in the order they are specified:
|
897
1239
|
|
898
1240
|
```ruby
|
899
1241
|
factory :user do
|
@@ -904,9 +1246,12 @@ end
|
|
904
1246
|
|
905
1247
|
Calling `create` will invoke both `after_build` and `after_create` callbacks.
|
906
1248
|
|
907
|
-
Also, like standard attributes, child factories will inherit (and can also
|
1249
|
+
Also, like standard attributes, child factories will inherit (and can also
|
1250
|
+
define) callbacks from their parent factory.
|
908
1251
|
|
909
|
-
Multiple callbacks can be assigned to run a block; this is useful when building
|
1252
|
+
Multiple callbacks can be assigned to run a block; this is useful when building
|
1253
|
+
various strategies that run the same code (since there are no callbacks that are
|
1254
|
+
shared across all strategies).
|
910
1255
|
|
911
1256
|
```ruby
|
912
1257
|
factory :user do
|
@@ -916,6 +1261,8 @@ factory :user do
|
|
916
1261
|
end
|
917
1262
|
```
|
918
1263
|
|
1264
|
+
### Global callbacks
|
1265
|
+
|
919
1266
|
To override callbacks for all factories, define them within the
|
920
1267
|
`FactoryBot.define` block:
|
921
1268
|
|
@@ -930,7 +1277,9 @@ FactoryBot.define do
|
|
930
1277
|
end
|
931
1278
|
```
|
932
1279
|
|
933
|
-
|
1280
|
+
### Symbol#to_proc
|
1281
|
+
|
1282
|
+
You can call callbacks that rely on `Symbol#to_proc`:
|
934
1283
|
|
935
1284
|
```ruby
|
936
1285
|
# app/models/user.rb
|
@@ -953,8 +1302,9 @@ create(:user) # creates the user and confirms it
|
|
953
1302
|
Modifying factories
|
954
1303
|
-------------------
|
955
1304
|
|
956
|
-
If you're given a set of factories (say, from a gem developer) but want to
|
957
|
-
|
1305
|
+
If you're given a set of factories (say, from a gem developer) but want to
|
1306
|
+
change them to fit into your application better, you can modify that factory
|
1307
|
+
instead of creating a child factory and adding attributes there.
|
958
1308
|
|
959
1309
|
If a gem were to give you a User factory:
|
960
1310
|
|
@@ -1018,6 +1368,14 @@ To set the attributes for each of the factories, you can pass in a hash as you n
|
|
1018
1368
|
twenty_year_olds = build_list(:user, 25, date_of_birth: 20.years.ago)
|
1019
1369
|
```
|
1020
1370
|
|
1371
|
+
In order to set different attributes for each factory, these methods may be passed a block, with the factory and the index as parameters:
|
1372
|
+
|
1373
|
+
```ruby
|
1374
|
+
twenty_somethings = build_list(:user, 10) do |user, i|
|
1375
|
+
user.date_of_birth = (20 + i).years.ago
|
1376
|
+
end
|
1377
|
+
```
|
1378
|
+
|
1021
1379
|
`build_stubbed_list` will give you fully stubbed out instances:
|
1022
1380
|
|
1023
1381
|
```ruby
|
@@ -1040,7 +1398,7 @@ users_attrs = attributes_for_list(:user, 25) # array of attribute hashes
|
|
1040
1398
|
Linting Factories
|
1041
1399
|
-----------------
|
1042
1400
|
|
1043
|
-
|
1401
|
+
factory\_bot allows for linting known factories:
|
1044
1402
|
|
1045
1403
|
```ruby
|
1046
1404
|
FactoryBot.lint
|
@@ -1066,7 +1424,7 @@ Example Rake task:
|
|
1066
1424
|
namespace :factory_bot do
|
1067
1425
|
desc "Verify that all FactoryBot factories are valid"
|
1068
1426
|
task lint: :environment do
|
1069
|
-
if Rails.env.test?
|
1427
|
+
if Rails.env.test?
|
1070
1428
|
conn = ActiveRecord::Base.connection
|
1071
1429
|
conn.transaction do
|
1072
1430
|
FactoryBot.lint
|
@@ -1126,7 +1484,7 @@ FactoryBot.lint verbose: true
|
|
1126
1484
|
Custom Construction
|
1127
1485
|
-------------------
|
1128
1486
|
|
1129
|
-
If you want to use
|
1487
|
+
If you want to use factory\_bot to construct an object where some attributes
|
1130
1488
|
are passed to `initialize` or if you want to do something other than simply
|
1131
1489
|
calling `new` on your build class, you can override the default behavior by
|
1132
1490
|
defining `initialize_with` on your factory. Example:
|
@@ -1154,7 +1512,7 @@ end
|
|
1154
1512
|
build(:user).name # Jane Doe
|
1155
1513
|
```
|
1156
1514
|
|
1157
|
-
Although
|
1515
|
+
Although factory\_bot is written to work with ActiveRecord out of the box, it
|
1158
1516
|
can also work with any Ruby class. For maximum compatibility with ActiveRecord,
|
1159
1517
|
the default initializer builds all instances by calling `new` on your build class
|
1160
1518
|
without any arguments. It then calls attribute writer methods to assign all the
|
@@ -1165,7 +1523,7 @@ You can override the initializer in order to:
|
|
1165
1523
|
|
1166
1524
|
* Build non-ActiveRecord objects that require arguments to `initialize`
|
1167
1525
|
* Use a method other than `new` to instantiate the instance
|
1168
|
-
* Do
|
1526
|
+
* Do wild things like decorate the instance after it's built
|
1169
1527
|
|
1170
1528
|
When using `initialize_with`, you don't have to declare the class itself when
|
1171
1529
|
calling `new`; however, any other class methods you want to call will have to
|
@@ -1227,7 +1585,7 @@ build(:user)
|
|
1227
1585
|
User.new('value')
|
1228
1586
|
```
|
1229
1587
|
|
1230
|
-
This prevents duplicate assignment; in versions of
|
1588
|
+
This prevents duplicate assignment; in versions of factory\_bot before 4.0, it
|
1231
1589
|
would run this:
|
1232
1590
|
|
1233
1591
|
```ruby
|
@@ -1413,12 +1771,12 @@ with associations, as below:
|
|
1413
1771
|
|
1414
1772
|
```ruby
|
1415
1773
|
FactoryBot.define do
|
1416
|
-
factory :united_states, class: Location do
|
1774
|
+
factory :united_states, class: "Location" do
|
1417
1775
|
name { 'United States' }
|
1418
1776
|
association :location_group, factory: :north_america
|
1419
1777
|
end
|
1420
1778
|
|
1421
|
-
factory :north_america, class: LocationGroup do
|
1779
|
+
factory :north_america, class: "LocationGroup" do
|
1422
1780
|
name { 'North America' }
|
1423
1781
|
end
|
1424
1782
|
end
|