factory_girl 3.1.1 → 3.2.0
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.
- data/.simplecov +4 -0
- data/GETTING_STARTED.md +147 -3
- data/Gemfile.lock +1 -1
- data/NEWS +8 -0
- data/features/support/env.rb +0 -1
- data/gemfiles/3.0.gemfile.lock +1 -1
- data/gemfiles/3.1.gemfile.lock +1 -1
- data/gemfiles/3.2.gemfile.lock +1 -1
- data/lib/factory_girl.rb +50 -7
- data/lib/factory_girl/attribute.rb +1 -1
- data/lib/factory_girl/attribute/association.rb +1 -1
- data/lib/factory_girl/attribute/dynamic.rb +1 -1
- data/lib/factory_girl/attribute/sequence.rb +1 -1
- data/lib/factory_girl/attribute/static.rb +1 -1
- data/lib/factory_girl/attribute_assigner.rb +12 -3
- data/lib/factory_girl/callback.rb +4 -1
- data/lib/factory_girl/{callback_runner.rb → callbacks_observer.rb} +1 -1
- data/lib/factory_girl/definition.rb +1 -1
- data/lib/factory_girl/definition_proxy.rb +4 -0
- data/lib/factory_girl/disallows_duplicates_registry.rb +17 -0
- data/lib/factory_girl/evaluator.rb +14 -11
- data/lib/factory_girl/factory.rb +5 -5
- data/lib/factory_girl/null_object.rb +14 -2
- data/lib/factory_girl/registry.rb +15 -23
- data/lib/factory_girl/reload.rb +2 -0
- data/lib/factory_girl/strategy_calculator.rb +1 -5
- data/lib/factory_girl/syntax.rb +1 -0
- data/lib/factory_girl/syntax/blueprint.rb +1 -0
- data/lib/factory_girl/syntax/generate.rb +6 -3
- data/lib/factory_girl/syntax/make.rb +4 -2
- data/lib/factory_girl/syntax/methods.rb +0 -81
- data/lib/factory_girl/syntax/sham.rb +1 -0
- data/lib/factory_girl/syntax/vintage.rb +0 -2
- data/lib/factory_girl/syntax_runner.rb +5 -0
- data/lib/factory_girl/version.rb +1 -1
- data/spec/acceptance/activesupport_instrumentation_spec.rb +49 -0
- data/spec/acceptance/build_stubbed_spec.rb +6 -6
- data/spec/acceptance/initialize_with_spec.rb +26 -0
- data/spec/acceptance/modify_factories_spec.rb +2 -2
- data/spec/acceptance/register_strategies_spec.rb +120 -0
- data/spec/acceptance/skip_create_spec.rb +19 -0
- data/spec/acceptance/syntax/blueprint_spec.rb +2 -0
- data/spec/acceptance/syntax/generate_spec.rb +2 -0
- data/spec/acceptance/syntax/make_spec.rb +2 -0
- data/spec/acceptance/syntax/vintage_spec.rb +2 -2
- data/spec/acceptance/syntax_methods_within_dynamic_attributes_spec.rb +41 -0
- data/spec/factory_girl/attribute/dynamic_spec.rb +6 -6
- data/spec/factory_girl/attribute_list_spec.rb +4 -4
- data/spec/factory_girl/callback_spec.rb +7 -7
- data/spec/factory_girl/definition_proxy_spec.rb +6 -6
- data/spec/factory_girl/disallows_duplicates_registry_spec.rb +44 -0
- data/spec/factory_girl/evaluator_class_definer_spec.rb +5 -5
- data/spec/factory_girl/factory_spec.rb +3 -3
- data/spec/factory_girl/null_object_spec.rb +18 -4
- data/spec/factory_girl/registry_spec.rb +30 -72
- data/spec/factory_girl/sequence_spec.rb +3 -2
- data/spec/factory_girl/strategy_calculator_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -1
- metadata +41 -28
data/.simplecov
ADDED
data/GETTING_STARTED.md
CHANGED
@@ -130,6 +130,24 @@ factory :user do
|
|
130
130
|
end
|
131
131
|
```
|
132
132
|
|
133
|
+
In addition to running other methods dynamically, you can use FactoryGirl's
|
134
|
+
syntax methods (like `build`, `create`, and `generate`) within dynamic
|
135
|
+
attributes without having to prefix the call with `FactoryGirl.`. This allows
|
136
|
+
you to do:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
sequence(:random_string) {|n| LoremIpsum.generate }
|
140
|
+
|
141
|
+
factory :post do
|
142
|
+
title { generate(:random_string) } # instead of FactoryGirl.generate(:random_string)
|
143
|
+
end
|
144
|
+
|
145
|
+
factory :comment do
|
146
|
+
post
|
147
|
+
body { generate(:random_string) } # instead of FactoryGirl.generate(:random_string)
|
148
|
+
end
|
149
|
+
```
|
150
|
+
|
133
151
|
Aliases
|
134
152
|
-------
|
135
153
|
|
@@ -372,7 +390,7 @@ Or in lazy attributes:
|
|
372
390
|
|
373
391
|
```ruby
|
374
392
|
factory :invite do
|
375
|
-
invitee {
|
393
|
+
invitee { generate(:email) }
|
376
394
|
end
|
377
395
|
```
|
378
396
|
|
@@ -684,7 +702,7 @@ Custom Construction
|
|
684
702
|
If you want to use factory_girl to construct an object where some attributes
|
685
703
|
are passed to `initialize` or if you want to do something other than simply
|
686
704
|
calling `new` on your build class, you can override the default behavior by
|
687
|
-
defining `
|
705
|
+
defining `initialize_with` on your factory. Example:
|
688
706
|
|
689
707
|
```ruby
|
690
708
|
# user.rb
|
@@ -705,7 +723,7 @@ factory :user do
|
|
705
723
|
end
|
706
724
|
|
707
725
|
email
|
708
|
-
initialize_with {
|
726
|
+
initialize_with { new(name) }
|
709
727
|
end
|
710
728
|
|
711
729
|
FactoryGirl.build(:user).name # Bob Hope
|
@@ -727,6 +745,132 @@ You can override the initializer in order to:
|
|
727
745
|
* Use a method other than `new` to instantiate the instance
|
728
746
|
* Do crazy things like decorate the instance after it's built
|
729
747
|
|
748
|
+
When using `initialize_with`, you don't have to declare the class itself when
|
749
|
+
calling `new`; however, any other class methods you want to call will have to
|
750
|
+
be called on the class explicitly.
|
751
|
+
|
752
|
+
For example:
|
753
|
+
|
754
|
+
```ruby
|
755
|
+
factory :user do
|
756
|
+
ignore do
|
757
|
+
name { Faker::Name.name }
|
758
|
+
end
|
759
|
+
|
760
|
+
initialize_with { User.build_with_name(name) }
|
761
|
+
end
|
762
|
+
```
|
763
|
+
|
764
|
+
Custom Strategies
|
765
|
+
-----------------
|
766
|
+
|
767
|
+
There are times where you may want to extend behavior of factory\_girl by
|
768
|
+
adding a custom build strategy.
|
769
|
+
|
770
|
+
Strategies define two methods: `association` and `result`. `association`
|
771
|
+
receives a `FactoryGirl::FactoryRunner` instance, upon which you can call
|
772
|
+
`run`, overriding the strategy if you want. The second method, `result`,
|
773
|
+
receives a `FactoryGirl::Evaluation` instance. It provides a way to trigger
|
774
|
+
callbacks (with `notify`), `object` or `hash` (to get the result instance or a
|
775
|
+
hash based on the attributes defined in the factory), and `create`, which
|
776
|
+
executes the `to_create` callback defined on the factory.
|
777
|
+
|
778
|
+
To understand how factory\_girl uses strategies internally, it's probably
|
779
|
+
easiest to just view the source for each of the four default strategies.
|
780
|
+
|
781
|
+
Inheritance can occasionally be useful; here's an example of inheriting from
|
782
|
+
`FactoryGirl::Strategy::Create` to build a JSON representation of your model.
|
783
|
+
|
784
|
+
```ruby
|
785
|
+
class JsonStrategy
|
786
|
+
def initialize
|
787
|
+
@strategy = FactoryGirl.strategy_by_name(:create).new
|
788
|
+
end
|
789
|
+
|
790
|
+
delegate :association, to: :@strategy
|
791
|
+
|
792
|
+
def result(evaluation)
|
793
|
+
@strategy.result(evaluation).to_json
|
794
|
+
end
|
795
|
+
end
|
796
|
+
```
|
797
|
+
|
798
|
+
For factory\_girl to recognize the new strategy, you can register it:
|
799
|
+
|
800
|
+
```ruby
|
801
|
+
FactoryGirl.register_strategy(:json, JsonStrategy)
|
802
|
+
```
|
803
|
+
|
804
|
+
This allows you to call
|
805
|
+
|
806
|
+
```ruby
|
807
|
+
FactoryGirl.json(:user)
|
808
|
+
```
|
809
|
+
|
810
|
+
Finally, you can override factory\_girl's own strategies if you'd like by
|
811
|
+
registering a new object in place of the strategies.
|
812
|
+
|
813
|
+
Custom Methods to Persist Objects
|
814
|
+
---------------------------------
|
815
|
+
|
816
|
+
By default, creating a record will call `save!` on the instance; since this
|
817
|
+
may not always be ideal, you can override that behavior by defining
|
818
|
+
`to_create` on the factory:
|
819
|
+
|
820
|
+
```ruby
|
821
|
+
factory :different_orm_model do
|
822
|
+
to_create {|instance| instance.persist! }
|
823
|
+
end
|
824
|
+
```
|
825
|
+
|
826
|
+
To disable the persistence method altogether on create, you can `skip_create`
|
827
|
+
for that factory:
|
828
|
+
|
829
|
+
```ruby
|
830
|
+
factory :user_without_database do
|
831
|
+
skip_create
|
832
|
+
end
|
833
|
+
```
|
834
|
+
|
835
|
+
ActiveSupport Instrumentation
|
836
|
+
-----------------------------
|
837
|
+
|
838
|
+
In order to track what factories are created (and with what build strategy),
|
839
|
+
`ActiveSupport::Notifications` are included to provide a way to subscribe to
|
840
|
+
factories being run. One example would be to track factories based on a
|
841
|
+
threshold of execution time.
|
842
|
+
|
843
|
+
```ruby
|
844
|
+
ActiveSupport::Notifications.subscribe("factory_girl.run_factory") do |name, start, finish, id, payload|
|
845
|
+
execution_time_in_seconds = finish - start
|
846
|
+
|
847
|
+
if execution_time_in_seconds >= 0.5
|
848
|
+
$stderr.puts "Slow factory: #{payload[:name]} using strategy #{payload[:strategy]}"
|
849
|
+
end
|
850
|
+
end
|
851
|
+
```
|
852
|
+
|
853
|
+
Another example would be tracking all factories and how they're used
|
854
|
+
throughout your test suite. If you're using RSpec, it's as simple as adding a
|
855
|
+
`before(:suite)` and `after(:suite)`:
|
856
|
+
|
857
|
+
```ruby
|
858
|
+
config.before(:suite) do
|
859
|
+
@factory_girl_results = {}
|
860
|
+
ActiveSupport::Notifications.subscribe("factory_girl.run_factory") do |name, start, finish, id, payload|
|
861
|
+
factory_name = payload[:name]
|
862
|
+
strategy_name = payload[:strategy]
|
863
|
+
@factory_girl_results[factory_name] ||= {}
|
864
|
+
@factory_girl_results[factory_name][strategy_name] ||= 0
|
865
|
+
@factory_girl_results[factory_name][strategy_name] += 1
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
869
|
+
config.after(:suite) do
|
870
|
+
puts @factory_girl_results
|
871
|
+
end
|
872
|
+
```
|
873
|
+
|
730
874
|
Cucumber Integration
|
731
875
|
--------------------
|
732
876
|
|
data/Gemfile.lock
CHANGED
data/NEWS
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
3.2.0 (April 24, 2012)
|
2
|
+
Use AS::Notifications for pub/sub to track running factories
|
3
|
+
Call new within initialize_with implicitly on the build class
|
4
|
+
Skip to_create with skip_create
|
5
|
+
Allow registration of custom strategies
|
6
|
+
Deprecate alternate syntaxes
|
7
|
+
Implicitly call factory_girl's syntax methods from dynamic attributes
|
8
|
+
|
1
9
|
3.1.0 (April 6, 2012)
|
2
10
|
Sequences support aliases, which reference the same block
|
3
11
|
Update documentation
|
data/features/support/env.rb
CHANGED
data/gemfiles/3.0.gemfile.lock
CHANGED
data/gemfiles/3.1.gemfile.lock
CHANGED
data/gemfiles/3.2.gemfile.lock
CHANGED
data/lib/factory_girl.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "active_support/core_ext/module/delegation"
|
2
|
+
require "active_support/notifications"
|
2
3
|
|
3
4
|
require 'factory_girl/errors'
|
4
5
|
require 'factory_girl/factory_runner'
|
@@ -8,6 +9,7 @@ require "factory_girl/strategy/create"
|
|
8
9
|
require "factory_girl/strategy/attributes_for"
|
9
10
|
require "factory_girl/strategy/stub"
|
10
11
|
require "factory_girl/strategy/null"
|
12
|
+
require 'factory_girl/disallows_duplicates_registry'
|
11
13
|
require 'factory_girl/registry'
|
12
14
|
require 'factory_girl/null_factory'
|
13
15
|
require 'factory_girl/null_object'
|
@@ -18,7 +20,7 @@ require 'factory_girl/evaluator'
|
|
18
20
|
require 'factory_girl/evaluator_class_definer'
|
19
21
|
require 'factory_girl/attribute'
|
20
22
|
require 'factory_girl/callback'
|
21
|
-
require 'factory_girl/
|
23
|
+
require 'factory_girl/callbacks_observer'
|
22
24
|
require 'factory_girl/declaration_list'
|
23
25
|
require 'factory_girl/declaration'
|
24
26
|
require 'factory_girl/sequence'
|
@@ -28,17 +30,21 @@ require 'factory_girl/aliases'
|
|
28
30
|
require 'factory_girl/definition'
|
29
31
|
require 'factory_girl/definition_proxy'
|
30
32
|
require 'factory_girl/syntax'
|
33
|
+
require 'factory_girl/syntax_runner'
|
31
34
|
require 'factory_girl/find_definitions'
|
32
35
|
require 'factory_girl/reload'
|
33
36
|
require 'factory_girl/version'
|
34
37
|
|
35
38
|
module FactoryGirl
|
36
39
|
def self.factories
|
37
|
-
@factories ||= Registry.new("Factory")
|
40
|
+
@factories ||= DisallowsDuplicatesRegistry.new(Registry.new("Factory"))
|
38
41
|
end
|
39
42
|
|
40
43
|
def self.register_factory(factory)
|
41
|
-
|
44
|
+
factory.names.each do |name|
|
45
|
+
factories.register(name, factory)
|
46
|
+
end
|
47
|
+
factory
|
42
48
|
end
|
43
49
|
|
44
50
|
def self.factory_by_name(name)
|
@@ -46,11 +52,14 @@ module FactoryGirl
|
|
46
52
|
end
|
47
53
|
|
48
54
|
def self.sequences
|
49
|
-
@sequences ||= Registry.new("Sequence")
|
55
|
+
@sequences ||= DisallowsDuplicatesRegistry.new(Registry.new("Sequence"))
|
50
56
|
end
|
51
57
|
|
52
58
|
def self.register_sequence(sequence)
|
53
|
-
|
59
|
+
sequence.names.each do |name|
|
60
|
+
sequences.register(name, sequence)
|
61
|
+
end
|
62
|
+
sequence
|
54
63
|
end
|
55
64
|
|
56
65
|
def self.sequence_by_name(name)
|
@@ -58,18 +67,52 @@ module FactoryGirl
|
|
58
67
|
end
|
59
68
|
|
60
69
|
def self.traits
|
61
|
-
@traits ||= Registry.new("Trait")
|
70
|
+
@traits ||= DisallowsDuplicatesRegistry.new(Registry.new("Trait"))
|
62
71
|
end
|
63
72
|
|
64
73
|
def self.register_trait(trait)
|
65
|
-
|
74
|
+
trait.names.each do |name|
|
75
|
+
traits.register(name, trait)
|
76
|
+
end
|
77
|
+
trait
|
66
78
|
end
|
67
79
|
|
68
80
|
def self.trait_by_name(name)
|
69
81
|
traits.find(name)
|
70
82
|
end
|
71
83
|
|
84
|
+
def self.strategies
|
85
|
+
@strategies ||= Registry.new("Strategy")
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.register_strategy(strategy_name, strategy_class)
|
89
|
+
strategies.register(strategy_name, strategy_class)
|
90
|
+
|
91
|
+
FactoryGirl::Syntax::Methods.module_exec do
|
92
|
+
define_method(strategy_name) do |name, *traits_and_overrides, &block|
|
93
|
+
instrumentation_payload = { name: name, strategy: strategy_name }
|
94
|
+
|
95
|
+
ActiveSupport::Notifications.instrument("factory_girl.run_factory", instrumentation_payload) do
|
96
|
+
FactoryRunner.new(name, strategy_class, traits_and_overrides).run(&block)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.strategy_by_name(name)
|
103
|
+
strategies.find(name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.register_default_strategies
|
107
|
+
FactoryGirl.register_strategy(:build, FactoryGirl::Strategy::Build)
|
108
|
+
FactoryGirl.register_strategy(:create, FactoryGirl::Strategy::Create)
|
109
|
+
FactoryGirl.register_strategy(:attributes_for, FactoryGirl::Strategy::AttributesFor)
|
110
|
+
FactoryGirl.register_strategy(:build_stubbed, FactoryGirl::Strategy::Stub)
|
111
|
+
end
|
112
|
+
|
72
113
|
def self.callback_names
|
73
114
|
[:after_build, :after_create, :after_stub, :before_create].freeze
|
74
115
|
end
|
75
116
|
end
|
117
|
+
|
118
|
+
FactoryGirl.register_default_strategies
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module FactoryGirl
|
2
2
|
class AttributeAssigner
|
3
|
-
def initialize(evaluator, &instance_builder)
|
3
|
+
def initialize(evaluator, build_class, &instance_builder)
|
4
|
+
@build_class = build_class
|
4
5
|
@instance_builder = instance_builder
|
5
6
|
@evaluator = evaluator
|
6
7
|
@attribute_list = evaluator.class.attribute_list
|
@@ -18,7 +19,7 @@ module FactoryGirl
|
|
18
19
|
end
|
19
20
|
|
20
21
|
def hash
|
21
|
-
@evaluator.instance =
|
22
|
+
@evaluator.instance = build_hash
|
22
23
|
|
23
24
|
attributes_to_set_on_hash.inject({}) do |result, attribute|
|
24
25
|
result[attribute] = get(attribute)
|
@@ -32,6 +33,10 @@ module FactoryGirl
|
|
32
33
|
@build_class_instance ||= @evaluator.instance_exec(&@instance_builder)
|
33
34
|
end
|
34
35
|
|
36
|
+
def build_hash
|
37
|
+
@build_hash ||= NullObject.new(hash_instance_methods_to_respond_to)
|
38
|
+
end
|
39
|
+
|
35
40
|
def get(attribute_name)
|
36
41
|
@evaluator.send(attribute_name)
|
37
42
|
end
|
@@ -61,7 +66,11 @@ module FactoryGirl
|
|
61
66
|
end
|
62
67
|
|
63
68
|
def override_names
|
64
|
-
@evaluator.
|
69
|
+
@evaluator.__override_names__
|
70
|
+
end
|
71
|
+
|
72
|
+
def hash_instance_methods_to_respond_to
|
73
|
+
@attribute_list.map(&:name) + override_names + @build_class.instance_methods
|
65
74
|
end
|
66
75
|
|
67
76
|
def alias_names_to_ignore
|