factory_bot 4.8.2 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +1 -0
  3. data/GETTING_STARTED.md +226 -129
  4. data/LICENSE +1 -1
  5. data/NAME.md +12 -5
  6. data/NEWS.md +351 -0
  7. data/README.md +35 -27
  8. data/lib/factory_bot/aliases.rb +1 -1
  9. data/lib/factory_bot/attribute/dynamic.rb +1 -0
  10. data/lib/factory_bot/attribute.rb +4 -39
  11. data/lib/factory_bot/attribute_assigner.rb +21 -6
  12. data/lib/factory_bot/attribute_list.rb +2 -1
  13. data/lib/factory_bot/callback.rb +3 -2
  14. data/lib/factory_bot/configuration.rb +16 -20
  15. data/lib/factory_bot/declaration/association.rb +14 -1
  16. data/lib/factory_bot/declaration/dynamic.rb +3 -1
  17. data/lib/factory_bot/declaration/implicit.rb +7 -2
  18. data/lib/factory_bot/declaration.rb +4 -4
  19. data/lib/factory_bot/declaration_list.rb +1 -1
  20. data/lib/factory_bot/decorator/attribute_hash.rb +1 -1
  21. data/lib/factory_bot/decorator/invocation_tracker.rb +1 -1
  22. data/lib/factory_bot/decorator.rb +5 -1
  23. data/lib/factory_bot/definition.rb +10 -7
  24. data/lib/factory_bot/definition_hierarchy.rb +1 -11
  25. data/lib/factory_bot/definition_proxy.rb +65 -41
  26. data/lib/factory_bot/errors.rb +7 -4
  27. data/lib/factory_bot/evaluation.rb +1 -1
  28. data/lib/factory_bot/evaluator.rb +5 -5
  29. data/lib/factory_bot/factory.rb +8 -8
  30. data/lib/factory_bot/factory_runner.rb +3 -3
  31. data/lib/factory_bot/find_definitions.rb +1 -1
  32. data/lib/factory_bot/internal.rb +104 -0
  33. data/lib/factory_bot/linter.rb +36 -19
  34. data/lib/factory_bot/null_factory.rb +4 -1
  35. data/lib/factory_bot/null_object.rb +2 -2
  36. data/lib/factory_bot/registry.rb +15 -6
  37. data/lib/factory_bot/reload.rb +3 -3
  38. data/lib/factory_bot/sequence.rb +9 -1
  39. data/lib/factory_bot/strategy/null.rb +2 -4
  40. data/lib/factory_bot/strategy/stub.rb +32 -36
  41. data/lib/factory_bot/strategy_calculator.rb +1 -1
  42. data/lib/factory_bot/strategy_syntax_method_registrar.rb +13 -2
  43. data/lib/factory_bot/syntax/default.rb +12 -24
  44. data/lib/factory_bot/syntax/methods.rb +32 -9
  45. data/lib/factory_bot/syntax.rb +2 -2
  46. data/lib/factory_bot/trait.rb +6 -3
  47. data/lib/factory_bot/version.rb +1 -1
  48. data/lib/factory_bot.rb +103 -134
  49. metadata +79 -64
  50. data/.autotest +0 -9
  51. data/.gitignore +0 -10
  52. data/.rspec +0 -2
  53. data/.simplecov +0 -4
  54. data/.travis.yml +0 -38
  55. data/Appraisals +0 -19
  56. data/Gemfile +0 -8
  57. data/Gemfile.lock +0 -103
  58. data/NEWS +0 -293
  59. data/Rakefile +0 -36
  60. data/cucumber.yml +0 -1
  61. data/factory_bot.gemspec +0 -36
  62. data/factory_girl.gemspec +0 -40
  63. data/gemfiles/3.2.gemfile +0 -10
  64. data/gemfiles/3.2.gemfile.lock +0 -105
  65. data/gemfiles/4.0.gemfile +0 -10
  66. data/gemfiles/4.0.gemfile.lock +0 -105
  67. data/gemfiles/4.1.gemfile +0 -10
  68. data/gemfiles/4.1.gemfile.lock +0 -104
  69. data/gemfiles/4.2.gemfile +0 -10
  70. data/gemfiles/4.2.gemfile.lock +0 -104
  71. data/gemfiles/5.0.gemfile +0 -10
  72. data/gemfiles/5.0.gemfile.lock +0 -103
  73. data/lib/factory_bot/attribute/static.rb +0 -16
  74. data/lib/factory_bot/declaration/static.rb +0 -26
  75. data/lib/factory_bot/decorator/class_key_hash.rb +0 -28
  76. data/lib/factory_girl.rb +0 -5
data/GETTING_STARTED.md CHANGED
@@ -4,16 +4,16 @@ Getting Started
4
4
  Update Your Gemfile
5
5
  -------------------
6
6
 
7
- If you're using Rails, you'll need to change the required version of `factory_bot_rails`:
7
+ If you're using Rails:
8
8
 
9
9
  ```ruby
10
- gem "factory_bot_rails", "~> 4.0"
10
+ gem "factory_bot_rails"
11
11
  ```
12
12
 
13
- If you're *not* using Rails, you'll just have to change the required version of `factory_bot`:
13
+ If you're *not* using Rails:
14
14
 
15
15
  ```ruby
16
- gem "factory_bot", "~> 4.0"
16
+ gem "factory_bot"
17
17
  ```
18
18
 
19
19
  JRuby users: factory_bot works with JRuby starting with 1.6.7.2 (latest stable, as per July 2012).
@@ -28,15 +28,19 @@ Once your Gemfile is updated, you'll want to update your bundle.
28
28
  Configure your test suite
29
29
  -------------------------
30
30
 
31
- # RSpec
31
+ ### RSpec
32
+
33
+ If you're using Rails, add the following configuration to `spec/support/factory_bot.rb` and be sure to require that file in `rails_helper.rb`:
32
34
 
33
35
  ```ruby
34
- # spec/support/factory_bot.rb
35
36
  RSpec.configure do |config|
36
37
  config.include FactoryBot::Syntax::Methods
37
38
  end
39
+ ```
38
40
 
39
- # RSpec without Rails
41
+ If you're *not* using Rails:
42
+
43
+ ```ruby
40
44
  RSpec.configure do |config|
41
45
  config.include FactoryBot::Syntax::Methods
42
46
 
@@ -46,13 +50,7 @@ RSpec.configure do |config|
46
50
  end
47
51
  ```
48
52
 
49
- Remember to require the above file in your rails_helper since the support folder isn't eagerly loaded
50
-
51
- ```ruby
52
- require 'support/factory_bot'
53
- ```
54
-
55
- # Test::Unit
53
+ ### Test::Unit
56
54
 
57
55
  ```ruby
58
56
  class Test::Unit::TestCase
@@ -60,14 +58,14 @@ class Test::Unit::TestCase
60
58
  end
61
59
  ```
62
60
 
63
- # Cucumber
61
+ ### Cucumber
64
62
 
65
63
  ```ruby
66
64
  # env.rb (Rails example location - RAILS_ROOT/features/support/env.rb)
67
65
  World(FactoryBot::Syntax::Methods)
68
66
  ```
69
67
 
70
- # Spinach
68
+ ### Spinach
71
69
 
72
70
  ```ruby
73
71
  class Spinach::FeatureSteps
@@ -75,7 +73,7 @@ class Spinach::FeatureSteps
75
73
  end
76
74
  ```
77
75
 
78
- # Minitest
76
+ ### Minitest
79
77
 
80
78
  ```ruby
81
79
  class Minitest::Unit::TestCase
@@ -83,7 +81,7 @@ class Minitest::Unit::TestCase
83
81
  end
84
82
  ```
85
83
 
86
- # Minitest::Spec
84
+ ### Minitest::Spec
87
85
 
88
86
  ```ruby
89
87
  class Minitest::Spec
@@ -91,7 +89,7 @@ class Minitest::Spec
91
89
  end
92
90
  ```
93
91
 
94
- # minitest-rails
92
+ ### minitest-rails
95
93
 
96
94
  ```ruby
97
95
  class ActiveSupport::TestCase
@@ -104,23 +102,42 @@ If you do not include `FactoryBot::Syntax::Methods` in your test suite, then all
104
102
  Defining factories
105
103
  ------------------
106
104
 
107
- Each factory has a name and a set of attributes. The name is used to guess the class of the object by default, but it's possible to explicitly specify it:
105
+ Each factory has a name and a set of attributes. The name is used to guess the class of the object by default:
108
106
 
109
107
  ```ruby
110
108
  # This will guess the User class
111
109
  FactoryBot.define do
112
110
  factory :user do
113
- first_name "John"
114
- last_name "Doe"
115
- admin false
111
+ first_name { "John" }
112
+ last_name { "Doe" }
113
+ admin { false }
116
114
  end
115
+ end
116
+ ```
117
117
 
118
- # This will use the User class (Admin would have been guessed)
119
- factory :admin, class: User do
120
- first_name "Admin"
121
- last_name "User"
122
- admin true
123
- end
118
+ It is also possible to explicitly specify the class:
119
+
120
+ ```ruby
121
+ # This will use the User class (otherwise Admin would have been guessed)
122
+ factory :admin, class: User
123
+ ```
124
+
125
+ If the constant is not available
126
+ (if you are using a Rails engine that waits to load models, for example),
127
+ you can also pass a symbol or string,
128
+ which factory_bot will constantize later, once you start building objects:
129
+
130
+ ```ruby
131
+ # It's OK if Doorkeeper::AccessToken isn't loaded yet
132
+ factory :access_token, class: "Doorkeeper::AccessToken"
133
+ ```
134
+
135
+ Because of the block syntax in Ruby, defining attributes as `Hash`es (for
136
+ serialized/JSON columns, for example) requires two sets of curly brackets:
137
+
138
+ ```ruby
139
+ factory :program do
140
+ configuration { { auto_resolve: false, auto_define: true } }
124
141
  end
125
142
  ```
126
143
 
@@ -170,40 +187,24 @@ user.first_name
170
187
  # => "Joe"
171
188
  ```
172
189
 
173
- Dynamic Attributes
174
- ------------------
175
-
176
- Most factory attributes can be added using static values that are evaluated when
177
- the factory is defined, but some attributes (such as associations and other
178
- attributes that must be dynamically generated) will need values assigned each
179
- time an instance is generated. These "dynamic" attributes can be added by passing a
180
- block instead of a parameter:
181
-
182
- ```ruby
183
- factory :user do
184
- # ...
185
- activation_code { User.generate_activation_code }
186
- date_of_birth { 21.years.ago }
187
- end
188
- ```
190
+ Note that objects created with `build_stubbed` cannot be serialized with
191
+ `Marshal.dump`, since factory_bot defines singleton methods on these objects.
189
192
 
190
- Because of the block syntax in Ruby, defining attributes as `Hash`es (for
191
- serialized/JSON columns, for example) requires two sets of curly brackets:
193
+ Static Attributes
194
+ ------------------
192
195
 
193
- ```ruby
194
- factory :program do
195
- configuration { { auto_resolve: false, auto_define: true } }
196
- end
197
- ```
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).
198
199
 
199
200
  Aliases
200
201
  -------
201
- factory_bot allows you to define aliases to existing factories to make them easier to re-use. This could come in handy when, for example, your Post object has an author attribute that actually refers to an instance of a User class. While normally factory_bot can infer the factory name from the association name, in this case it will look for a author factory in vain. So, alias your user factory so it can be used under alias names.
202
+ factory_bot allows you to define aliases to existing factories to make them easier to re-use. This could come in handy when, for example, your Post object has an author attribute that actually refers to an instance of a User class. While normally factory_bot can infer the factory name from the association name, in this case it will look for an author factory in vain. So, alias your user factory so it can be used under alias names.
202
203
 
203
204
  ```ruby
204
205
  factory :user, aliases: [:author, :commenter] do
205
- first_name "John"
206
- last_name "Doe"
206
+ first_name { "John" }
207
+ last_name { "Doe" }
207
208
  date_of_birth { 18.years.ago }
208
209
  end
209
210
 
@@ -211,15 +212,15 @@ factory :post do
211
212
  author
212
213
  # instead of
213
214
  # association :author, factory: :user
214
- title "How to read a book effectively"
215
- body "There are five steps involved."
215
+ title { "How to read a book effectively" }
216
+ body { "There are five steps involved." }
216
217
  end
217
218
 
218
219
  factory :comment do
219
220
  commenter
220
221
  # instead of
221
222
  # association :commenter, factory: :user
222
- body "Great article!"
223
+ body { "Great article!" }
223
224
  end
224
225
  ```
225
226
 
@@ -231,8 +232,8 @@ that is yielded to dynamic attribute blocks:
231
232
 
232
233
  ```ruby
233
234
  factory :user do
234
- first_name "Joe"
235
- last_name "Blow"
235
+ first_name { "Joe" }
236
+ last_name { "Blow" }
236
237
  email { "#{first_name}.#{last_name}@example.com".downcase }
237
238
  end
238
239
 
@@ -248,11 +249,11 @@ There may be times where your code can be DRYed up by passing in transient attri
248
249
  ```ruby
249
250
  factory :user do
250
251
  transient do
251
- rockstar true
252
- upcased false
252
+ rockstar { true }
253
+ upcased { false }
253
254
  end
254
255
 
255
- name { "John Doe#{" - Rockstar" if rockstar}" }
256
+ name { "John Doe#{" - Rockstar" if rockstar}" }
256
257
  email { "#{name.downcase}@example.com" }
257
258
 
258
259
  after(:create) do |user, evaluator|
@@ -264,8 +265,8 @@ create(:user, upcased: true).name
264
265
  #=> "JOHN DOE - ROCKSTAR"
265
266
  ```
266
267
 
267
- Static and dynamic attributes can be created as transient attributes. Transient
268
- attributes will be ignored within attributes\_for and won't be set on the model,
268
+ Transient attributes will be ignored within attributes\_for and won't be
269
+ set on the model,
269
270
  even if the attribute exists or you attempt to override it.
270
271
 
271
272
  Within factory_bot's dynamic attributes, you can access transient attributes as
@@ -276,7 +277,7 @@ transient attributes from there.
276
277
  Method Name / Reserved Word Attributes
277
278
  -------------------------------
278
279
 
279
- If your attributes conflict with existing methods or reserved words you can define them with `add_attribute`.
280
+ If your attributes conflict with existing methods or reserved words (all methods in the [DefinitionProxy](https://github.com/thoughtbot/factory_bot/blob/master/lib/factory_bot/definition_proxy.rb) class) you can define them with `add_attribute`.
280
281
 
281
282
  ```ruby
282
283
  factory :dna do
@@ -296,10 +297,10 @@ You can easily create multiple factories for the same class without repeating co
296
297
 
297
298
  ```ruby
298
299
  factory :post do
299
- title "A title"
300
+ title { "A title" }
300
301
 
301
302
  factory :approved_post do
302
- approved true
303
+ approved { true }
303
304
  end
304
305
  end
305
306
 
@@ -312,11 +313,11 @@ You can also assign the parent explicitly:
312
313
 
313
314
  ```ruby
314
315
  factory :post do
315
- title "A title"
316
+ title { "A title" }
316
317
  end
317
318
 
318
319
  factory :approved_post, parent: :post do
319
- approved true
320
+ approved { true }
320
321
  end
321
322
  ```
322
323
 
@@ -346,9 +347,35 @@ factory :post do
346
347
  end
347
348
  ```
348
349
 
349
- The behavior of the association method varies depending on the build strategy used for the parent object.
350
+ In factory\_bot 5, associations default to using the same build strategy as
351
+ their parent object:
352
+
353
+ ```ruby
354
+ FactoryBot.define do
355
+ factory :author
356
+
357
+ factory :post do
358
+ author
359
+ end
360
+ end
361
+
362
+ post = build(:post)
363
+ post.new_record? # => true
364
+ post.author.new_record? # => true
365
+
366
+ post = create(:post)
367
+ post.new_record? # => false
368
+ post.author.new_record? # => false
369
+ ```
370
+
371
+ This is different than the default behavior for previous versions of
372
+ factory\_bot, where the association strategy would not always match the strategy
373
+ of the parent object. If you want to continue using the old behavior, you can
374
+ set the `use_parent_strategy` configuration option to `false`.
350
375
 
351
376
  ```ruby
377
+ FactoryBot.use_parent_strategy = false
378
+
352
379
  # Builds and saves a User and a Post
353
380
  post = create(:post)
354
381
  post.new_record? # => false
@@ -360,9 +387,11 @@ post.new_record? # => true
360
387
  post.author.new_record? # => false
361
388
  ```
362
389
 
363
- To not save the associated object, specify strategy: :build in the factory:
390
+ To not save the associated object, specify `strategy: :build` in the factory:
364
391
 
365
392
  ```ruby
393
+ FactoryBot.use_parent_strategy = false
394
+
366
395
  factory :post do
367
396
  # ...
368
397
  association :author, factory: :user, strategy: :build
@@ -392,20 +421,20 @@ FactoryBot.define do
392
421
 
393
422
  # post factory with a `belongs_to` association for the user
394
423
  factory :post do
395
- title "Through the Looking Glass"
424
+ title { "Through the Looking Glass" }
396
425
  user
397
426
  end
398
427
 
399
428
  # user factory without associated posts
400
429
  factory :user do
401
- name "John Doe"
430
+ name { "John Doe" }
402
431
 
403
432
  # user_with_posts will create post data after the user has been created
404
433
  factory :user_with_posts do
405
434
  # posts_count is declared as a transient attribute and available in
406
435
  # attributes on the factory, as well as the callback via the evaluator
407
436
  transient do
408
- posts_count 5
437
+ posts_count { 5 }
409
438
  end
410
439
 
411
440
  # the after(:create) yields two values; the user instance itself and the
@@ -441,13 +470,13 @@ FactoryBot.define do
441
470
 
442
471
  # language factory with a `belongs_to` association for the profile
443
472
  factory :language do
444
- title "Through the Looking Glass"
473
+ title { "Through the Looking Glass" }
445
474
  profile
446
475
  end
447
476
 
448
477
  # profile factory without associated languages
449
478
  factory :profile do
450
- name "John Doe"
479
+ name { "John Doe" }
451
480
 
452
481
  # profile_with_languages will create language data after the profile has
453
482
  # been created
@@ -455,7 +484,7 @@ FactoryBot.define do
455
484
  # languages_count is declared as an ignored attribute and available in
456
485
  # attributes on the factory, as well as the callback via the evaluator
457
486
  transient do
458
- languages_count 5
487
+ languages_count { 5 }
459
488
  end
460
489
 
461
490
  # the after(:create) yields two values; the profile instance itself and
@@ -479,6 +508,36 @@ create(:profile_with_languages).languages.length # 5
479
508
  create(:profile_with_languages, languages_count: 15).languages.length # 15
480
509
  ```
481
510
 
511
+ Polymorphic associations can be handled with traits:
512
+
513
+ ```ruby
514
+ FactoryBot.define do
515
+ factory :video
516
+ factory :photo
517
+
518
+ factory :comment do
519
+ for_photo # default to the :for_photo trait if none is specified
520
+
521
+ trait :for_video do
522
+ association :commentable, factory: :video
523
+ end
524
+
525
+ trait :for_photo do
526
+ association :commentable, factory: :photo
527
+ end
528
+ end
529
+ end
530
+ ```
531
+
532
+ This allows us to do:
533
+
534
+ ```ruby
535
+ create(:comment)
536
+ create(:comment, :for_video)
537
+ create(:comment, :for_photo)
538
+ ```
539
+
540
+
482
541
  Sequences
483
542
  ---------
484
543
 
@@ -518,6 +577,9 @@ factory :user do
518
577
  end
519
578
  ```
520
579
 
580
+ Note that defining sequences as implicit attributes will not work if you have a
581
+ factory with the same name as the sequence.
582
+
521
583
  And it's also possible to define an in-line sequence that is only used in
522
584
  a particular factory:
523
585
 
@@ -572,6 +634,22 @@ end
572
634
 
573
635
  The value just needs to support the `#next` method. Here the next value will be 'a', then 'b', etc.
574
636
 
637
+ Sequences can also be rewound with `FactoryBot.rewind_sequences`:
638
+
639
+ ```ruby
640
+ sequence(:email) {|n| "person#{n}@example.com" }
641
+
642
+ generate(:email) # "person1@example.com"
643
+ generate(:email) # "person2@example.com"
644
+ generate(:email) # "person3@example.com"
645
+
646
+ FactoryBot.rewind_sequences
647
+
648
+ generate(:email) # "person1@example.com"
649
+ ```
650
+
651
+ This rewinds all registered sequences.
652
+
575
653
  Traits
576
654
  ------
577
655
 
@@ -582,25 +660,25 @@ to any factory.
582
660
  factory :user, aliases: [:author]
583
661
 
584
662
  factory :story do
585
- title "My awesome story"
663
+ title { "My awesome story" }
586
664
  author
587
665
 
588
666
  trait :published do
589
- published true
667
+ published { true }
590
668
  end
591
669
 
592
670
  trait :unpublished do
593
- published false
671
+ published { false }
594
672
  end
595
673
 
596
674
  trait :week_long_publishing do
597
675
  start_at { 1.week.ago }
598
- end_at { Time.now }
676
+ end_at { Time.now }
599
677
  end
600
678
 
601
679
  trait :month_long_publishing do
602
680
  start_at { 1.month.ago }
603
- end_at { Time.now }
681
+ end_at { Time.now }
604
682
  end
605
683
 
606
684
  factory :week_long_published_story, traits: [:published, :week_long_publishing]
@@ -610,7 +688,7 @@ factory :story do
610
688
  end
611
689
  ```
612
690
 
613
- Traits can be used as attributes:
691
+ Traits can be used as implicit attributes:
614
692
 
615
693
  ```ruby
616
694
  factory :week_long_published_story_with_title, parent: :story do
@@ -620,28 +698,31 @@ factory :week_long_published_story_with_title, parent: :story do
620
698
  end
621
699
  ```
622
700
 
701
+ Note that defining traits as implicit attributes will not work if you have a
702
+ factory or sequence with the same name as the trait.
703
+
623
704
  Traits that define the same attributes won't raise AttributeDefinitionErrors;
624
705
  the trait that defines the attribute latest gets precedence.
625
706
 
626
707
  ```ruby
627
708
  factory :user do
628
- name "Friendly User"
709
+ name { "Friendly User" }
629
710
  login { name }
630
711
 
631
712
  trait :male do
632
- name "John Doe"
633
- gender "Male"
713
+ name { "John Doe" }
714
+ gender { "Male" }
634
715
  login { "#{name} (M)" }
635
716
  end
636
717
 
637
718
  trait :female do
638
- name "Jane Doe"
639
- gender "Female"
719
+ name { "Jane Doe" }
720
+ gender { "Female" }
640
721
  login { "#{name} (F)" }
641
722
  end
642
723
 
643
724
  trait :admin do
644
- admin true
725
+ admin { true }
645
726
  login { "admin-#{name}" }
646
727
  end
647
728
 
@@ -654,18 +735,18 @@ You can also override individual attributes granted by a trait in subclasses.
654
735
 
655
736
  ```ruby
656
737
  factory :user do
657
- name "Friendly User"
738
+ name { "Friendly User" }
658
739
  login { name }
659
740
 
660
741
  trait :male do
661
- name "John Doe"
662
- gender "Male"
742
+ name { "John Doe" }
743
+ gender { "Male" }
663
744
  login { "#{name} (M)" }
664
745
  end
665
746
 
666
747
  factory :brandon do
667
748
  male
668
- name "Brandon"
749
+ name { "Brandon" }
669
750
  end
670
751
  end
671
752
  ```
@@ -674,15 +755,15 @@ Traits can also be passed in as a list of symbols when you construct an instance
674
755
 
675
756
  ```ruby
676
757
  factory :user do
677
- name "Friendly User"
758
+ name { "Friendly User" }
678
759
 
679
760
  trait :male do
680
- name "John Doe"
681
- gender "Male"
761
+ name { "John Doe" }
762
+ gender { "Male" }
682
763
  end
683
764
 
684
765
  trait :admin do
685
- admin true
766
+ admin { true }
686
767
  end
687
768
  end
688
769
 
@@ -698,10 +779,10 @@ the number of instances to create/build as second parameter, as documented in th
698
779
 
699
780
  ```ruby
700
781
  factory :user do
701
- name "Friendly User"
782
+ name { "Friendly User" }
702
783
 
703
784
  trait :admin do
704
- admin true
785
+ admin { true }
705
786
  end
706
787
  end
707
788
 
@@ -713,10 +794,10 @@ Traits can be used with associations easily too:
713
794
 
714
795
  ```ruby
715
796
  factory :user do
716
- name "Friendly User"
797
+ name { "Friendly User" }
717
798
 
718
799
  trait :admin do
719
- admin true
800
+ admin { true }
720
801
  end
721
802
  end
722
803
 
@@ -732,10 +813,10 @@ When you're using association names that're different than the factory:
732
813
 
733
814
  ```ruby
734
815
  factory :user do
735
- name "Friendly User"
816
+ name { "Friendly User" }
736
817
 
737
818
  trait :admin do
738
- admin true
819
+ admin { true }
739
820
  end
740
821
  end
741
822
 
@@ -770,7 +851,7 @@ Finally, traits can accept transient attributes.
770
851
  factory :invoice do
771
852
  trait :with_amount do
772
853
  transient do
773
- amount 1
854
+ amount { 1 }
774
855
  end
775
856
 
776
857
  after(:create) do |invoice, evaluator|
@@ -844,7 +925,7 @@ FactoryBot.define do
844
925
  after(:create) { |object| AuditLog.create(attrs: object.attributes) }
845
926
 
846
927
  factory :user do
847
- name "John Doe"
928
+ name { "John Doe" }
848
929
  end
849
930
  end
850
931
  ```
@@ -880,9 +961,9 @@ If a gem were to give you a User factory:
880
961
  ```ruby
881
962
  FactoryBot.define do
882
963
  factory :user do
883
- full_name "John Doe"
964
+ full_name { "John Doe" }
884
965
  sequence(:username) { |n| "user#{n}" }
885
- password "password"
966
+ password { "password" }
886
967
  end
887
968
  end
888
969
  ```
@@ -892,10 +973,10 @@ Instead of creating a child factory that added additional attributes:
892
973
  ```ruby
893
974
  FactoryBot.define do
894
975
  factory :application_user, parent: :user do
895
- full_name "Jane Doe"
976
+ full_name { "Jane Doe" }
896
977
  date_of_birth { 21.years.ago }
897
- gender "Female"
898
- health 90
978
+ gender { "Female" }
979
+ health { 90 }
899
980
  end
900
981
  end
901
982
  ```
@@ -905,10 +986,10 @@ You could modify that factory instead.
905
986
  ```ruby
906
987
  FactoryBot.modify do
907
988
  factory :user do
908
- full_name "Jane Doe"
989
+ full_name { "Jane Doe" }
909
990
  date_of_birth { 21.years.ago }
910
- gender "Female"
911
- health 90
991
+ gender { "Female" }
992
+ health { 90 }
912
993
  end
913
994
  end
914
995
  ```
@@ -937,6 +1018,14 @@ To set the attributes for each of the factories, you can pass in a hash as you n
937
1018
  twenty_year_olds = build_list(:user, 25, date_of_birth: 20.years.ago)
938
1019
  ```
939
1020
 
1021
+ In order to set different attributes for each factory, these methods may be passed a block, with the factory and the index as parameters:
1022
+
1023
+ ```ruby
1024
+ twenty_somethings = build_list(:user, 10) do |user, i|
1025
+ user.date_of_birth = (20 + i).years.ago
1026
+ end
1027
+ ```
1028
+
940
1029
  `build_stubbed_list` will give you fully stubbed out instances:
941
1030
 
942
1031
  ```ruby
@@ -986,12 +1075,14 @@ namespace :factory_bot do
986
1075
  desc "Verify that all FactoryBot factories are valid"
987
1076
  task lint: :environment do
988
1077
  if Rails.env.test?
989
- DatabaseCleaner.cleaning do
1078
+ conn = ActiveRecord::Base.connection
1079
+ conn.transaction do
990
1080
  FactoryBot.lint
1081
+ raise ActiveRecord::Rollback
991
1082
  end
992
1083
  else
993
1084
  system("bundle exec rake factory_bot:lint RAILS_ENV='test'")
994
- exit $?.exitstatus
1085
+ fail if $?.exitstatus.nonzero?
995
1086
  end
996
1087
  end
997
1088
  end
@@ -999,8 +1090,7 @@ end
999
1090
 
1000
1091
  After calling `FactoryBot.lint`, you'll likely want to clear out the
1001
1092
  database, as records will most likely be created. The provided example above
1002
- uses the database_cleaner gem to clear out the database; be sure to add the
1003
- gem to your Gemfile under the appropriate groups.
1093
+ uses an sql transaction and rollback to leave the database clean.
1004
1094
 
1005
1095
  You can lint factories selectively by passing only factories you want linted:
1006
1096
 
@@ -1034,6 +1124,13 @@ You can also specify the strategy used for linting:
1034
1124
  FactoryBot.lint strategy: :build
1035
1125
  ```
1036
1126
 
1127
+ Verbose linting will include full backtraces for each error, which can be
1128
+ helpful for debugging:
1129
+
1130
+ ```ruby
1131
+ FactoryBot.lint verbose: true
1132
+ ```
1133
+
1037
1134
  Custom Construction
1038
1135
  -------------------
1039
1136
 
@@ -1056,7 +1153,7 @@ end
1056
1153
  sequence(:email) { |n| "person#{n}@example.com" }
1057
1154
 
1058
1155
  factory :user do
1059
- name "Jane Doe"
1156
+ name { "Jane Doe" }
1060
1157
  email
1061
1158
 
1062
1159
  initialize_with { new(name) }
@@ -1086,7 +1183,7 @@ For example:
1086
1183
 
1087
1184
  ```ruby
1088
1185
  factory :user do
1089
- name "John Doe"
1186
+ name { "John Doe" }
1090
1187
 
1091
1188
  initialize_with { User.build_with_name(name) }
1092
1189
  end
@@ -1098,7 +1195,7 @@ by calling `attributes`:
1098
1195
  ```ruby
1099
1196
  factory :user do
1100
1197
  transient do
1101
- comments_count 5
1198
+ comments_count { 5 }
1102
1199
  end
1103
1200
 
1104
1201
  name "John Doe"
@@ -1109,7 +1206,7 @@ end
1109
1206
 
1110
1207
  This will build a hash of all attributes to be passed to `new`. It won't
1111
1208
  include transient attributes, but everything else defined in the factory will be
1112
- passed (associations, evalued sequences, etc.)
1209
+ passed (associations, evaluated sequences, etc.)
1113
1210
 
1114
1211
  You can define `initialize_with` for all factories by including it in the
1115
1212
  `FactoryBot.define` block:
@@ -1271,7 +1368,7 @@ FactoryBot.define do
1271
1368
 
1272
1369
 
1273
1370
  factory :user do
1274
- name "John Doe"
1371
+ name { "John Doe" }
1275
1372
  end
1276
1373
  end
1277
1374
  ```
@@ -1324,13 +1421,13 @@ with associations, as below:
1324
1421
 
1325
1422
  ```ruby
1326
1423
  FactoryBot.define do
1327
- factory :united_states, class: Location do
1328
- name 'United States'
1424
+ factory :united_states, class: "Location" do
1425
+ name { 'United States' }
1329
1426
  association :location_group, factory: :north_america
1330
1427
  end
1331
1428
 
1332
- factory :north_america, class: LocationGroup do
1333
- name 'North America'
1429
+ factory :north_america, class: "LocationGroup" do
1430
+ name { 'North America' }
1334
1431
  end
1335
1432
  end
1336
1433
  ```
@@ -1362,7 +1459,7 @@ require 'factory_bot'
1362
1459
  ```
1363
1460
 
1364
1461
  Once required, assuming you have a directory structure of `spec/factories` or
1365
- `test/factories`, all you'll need to do is run
1462
+ `test/factories`, all you'll need to do is run:
1366
1463
 
1367
1464
  ```ruby
1368
1465
  FactoryBot.find_definitions
@@ -1384,7 +1481,7 @@ require 'factory_bot'
1384
1481
 
1385
1482
  FactoryBot.define do
1386
1483
  factory :user do
1387
- name 'John Doe'
1484
+ name { 'John Doe' }
1388
1485
  date_of_birth { 21.years.ago }
1389
1486
  end
1390
1487
  end