factory_girl 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|